Introdução
A motivação do Artigo veio através de uma dificuldade que tive estudando Plugs em Elixir, o conteúdo não exemplificava e/ou explicava muito bem o funcionamento desse tipo de componente, e após muito estudo consegui uma forma interessante para entender tudo isso, e nada melhor do que compartilhar esse estudo!
Dessa forma, artigo de hoje tem o intuito de explicar o funcionamento dos Plugs em Elixir por meio das seguintes etapas abaixo. No entanto, é de SUMA importância que você tenha conhecimento do protocolo HTTP e do ciclo de vida das requisições, pois isso não será abordado no texto abaixo:
-
Middlewares: Um breve resumo
- Tipos comuns de middlewares utilizados em Elixir
-
Plugs em Elixir!
- Elementos e caminhos de um Plug
-
Tipos de Plugs em Elixir
- Function Plugs
- Module Plugs
Plug Pipelines
1 - Middlewares: Um breve resumo
Middleware é um tipo de software que gerencia dados e informações de um determinado tipo de aplicação, seja ela um sistema de mensageria, autenticação, API, dentre outros. Dessa forma, o middleware atua como uma "ponte" entre os processos do software, possibilitando a criação de aplicações mais legíveis e eficientes, uma vez que o desenvolvedor entenda todos os processos de seu middleware, onde as conexões e dados do usuário final sejam tratadas de forma integral e legível pelo programa.
1.1 - Tipos comuns de middlewares utilizados em Elixir
Integração abrangente: Esse middleware possibilita conectar sistemas internos e externos da aplicação, facilitando a tratativa dos dados recebidos, temos como exemplo uma linha de autenticação por token, onde o usuário envia a primeira requisição com seus dados e em seguida ganha um "Token" para continuar navegando em outras áreas de um determinado site. Em elixir temos libs que disponibilizam plugs para isso.
API's: As nossas boas e velhas APi's também são tipos de middlewares, uma vez que as mesmas também podem ser ferramentas integradas por meio de protocolos, transmitindo e/ou tratando dados para uma aplicação e podendo conectar os produtos e serviços de um software.
2 - Plugs em Elixir!
Em Elixir, o Plug é o que possibilita diferentes frameworks se comunicarem com diferentes servidores na VM do Erlang, atuando como um Middleware. Entender os Plugs é algo vital para um bom desenvolvedor Elixir, uma vez que grande parte do ecossistema de uma aplicação e seus frameworks é feita por meio de Plugs.
Os Plugs vão interagir em todas as etapas de uma aplicação, sejam elas controllers, endpoints ou routers, e internamente, todos são plugs.
A intenção principal de um Plug é unificar o conceito de "Connection" (isso não será traduzido, pois, será tratado como elementos e parâmetros em Elixir, e é uma convenção abreviar tal parâmetro) ou "Conn". Dessa forma, o Plug difere-se de outros middlewares que utilizam desse mesmo sistema de Connections, pois internamente ele não separa a requisição da resposta.
2.1 - Elementos e caminhos de um Plug
É possível pensar em um Plug como um trecho do código que recebe uma estrutura de dados, transforma-a e retorna a mesma estrutura, porém, com algum tipo de transformação. A estrutura principal recebida pelo Plug é a "Connection", que representa tudo em uma requisição.
Desse modo, ao receber a Connection por meio da estrutura de dados %{} - "struct", a mesma será transformada progressivamente por meio do que chamamos de "Plug pipeline" até a resposta final que precisamos.
Essa Connection que utilizaremos sempre é chamada de %Plug.Conn{}, uma struct onde armazenaremos as informações da nossa requisição, você pode consultar a documentação da mesma aqui.
3 - Tipos de Plugs em Elixir
Em seu nível mais simples, os Plugs dividem-se em duas formas: Function Plugs e Module Plugs.
3.1 - Function Plugs
Para atuar como um Plug, uma função precisa de duas coisas:
Aceitar uma Connection struct ( %Plug.Conn{} ).
Retornar uma Connection struct
Toda função que receber e retornar tais parâmetros pode ser chamada Function plug.
Temos como exemplo:
def connection_example(conn, _opts) do
conn
end
Explicando o código:
Elementos:
conn: struct %Plug.Conn{}.
_opts: abreviação para "options", como não será utilizada e, por convenção em elixir, é colocado um underscore ( _ ) para ignorar os valores.
Comportamento:
- Receberá a connection e as options (que não utilizaremos).
3.2 - Module Plugs
É considerado Module Plug tudo aquilo que implementa as duas funções: init/1 e call/2:
defmodule PlugExample do
def init(opts) do
opts
end
def call(conn, opts) do
conn
end
end
Explicando o código:
Elementos:
função init/1
função call/2
Comportamento:
init receberá um parâmetro (options) e retornará o parâmetro recebido.
-
call receberá dois parâmetros: a connection e as options de init/1, agilizando muito o processo de execução do programa.
- Curiosidade: init/1 é executada enquanto o programa é compilado, enquanto call/2 acontece enquanto o programa está sendo executado.
Um exemplo
Para não deixar esse artigo gigante, você pode consultar um exemplo funcional de um MODULE PLUG no meu github
Plug pipelines
Os Plugs começam a tomar sentido quando começamos a utilizar pipelines, que nada mais é do que um jeito de aninhar os Plugs, cada um fazendo uma pequena tarefa, transformando os dados e mandando-os para o próximo Plug de forma sequencial.
Tal coisa é muito utilizada no Phoenix, o framework para aplicações Web do Elixir, de modo que temos a seguinte pipeline como padrão:
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
Dessa forma, cada requisição terá como retorno uma Connection modificada, que será passada para outros plugs até chegarmos a uma resposta final.
Conclusão
Com esse artigo, é possível entender o que é um middleware, Plugs em Elixir, Tipos de Plugs e Plug pipelines, não será possível, nessa ocasião, a construção de um Plug em Phoenix. No entanto, farei um artigo futuramente detalhando passo-a-passo a criação de um Plug desde o mix phx.new
até o término do código.
No mais, espero que eu tenha conseguido clarear um pouco a ideia dos Plugs, e qualquer dúvida e/ou correções é possível me contatar no twitter!
Top comments (9)
Muito massa o texto maninho, parabéns e obrigado por compartilhar o conteúdo!
Uma das coisas que mais admiro no Elixir, é esse princípio de Composability que é muito utilizado, como no exemplo que você deu de aninhar plugs em uma pipeline, que também pode ser usado no Ecto para aninhar queries, ou até mesmo no Elixir com o pipe operator!
Muito obrigado pelo feedback, irmão! e agradeço mais ainda por ter me incentivado a buscar esse conteúdo e trazê-lo em português!
Exatamente! Composability em Elixir é incrível em todas as formas!
Ótimo artigo! Parabéns Paulo, ficou realmente muito bom! :')
Agradeço demais pelo feedback, Rômulo! Você é uma inspiração p mim!
Parabéns pelo artigo! Didática impecavel, sempre.
Valeuuuu Douglão, você é o melhor!
incrivel explicação👌👏
Mt obg!
Muito bom!