Introdução ao desenvolvimento web com Gleam e frameworks emergentes na BEAM
1. Fundamentos do Gleam na BEAM
1.1. O que é Gleam: tipagem estática e sintaxe familiar para a máquina virtual Erlang (BEAM)
Gleam é uma linguagem de programação moderna que compila para a BEAM (Bogdan/Björn's Erlang Abstract Machine), a mesma máquina virtual que executa Erlang e Elixir. Sua principal característica é oferecer um sistema de tipos estáticos rigoroso, inspirado em linguagens como Haskell e Elm, combinado com uma sintaxe limpa e familiar para desenvolvedores que já trabalham com JavaScript, Python ou Rust.
// Exemplo básico de Gleam
pub fn saudacao(nome: String) -> String {
"Olá, " <> nome <> "!"
}
pub fn main() {
let mensagem = saudacao("Mundo")
io.println(mensagem)
}
1.2. Vantagens da BEAM para web: concorrência leve, tolerância a falhas e escalabilidade
A BEAM foi projetada originalmente para sistemas telefônicos, onde falhas não são aceitáveis. Isso se traduz em três grandes vantagens para aplicações web:
- Concorrência leve: processos BEAM são extremamente leves (alguns kilobytes cada), permitindo milhões de processos simultâneos sem sobrecarga significativa.
- Tolerância a falhas: o modelo "let it crash" permite que processos falhem sem derrubar todo o sistema, com supervisores reiniciando automaticamente.
- Escalabilidade: distribuição nativa entre nós, permitindo escalar horizontalmente com facilidade.
1.3. Configurando o ambiente: instalação do Gleam, compilador e ferramentas de build
Para começar, instale o compilador Gleam e as ferramentas necessárias:
# Instalação via script oficial (Linux/macOS)
curl -fsSL https://gleam.run/get | bash
# Verificar instalação
gleam --version
# Criar um novo projeto
gleam new meu_projeto_web
cd meu_projeto_web
# Compilar e executar
gleam build
gleam run
2. Primeiros passos com uma aplicação web em Gleam
2.1. Estrutura de um projeto web: dependências, módulos e ponto de entrada
Um projeto Gleam típico para web possui a seguinte estrutura:
meu_projeto_web/
├── gleam.toml # Configuração do projeto e dependências
├── manifest.toml # Lockfile de dependências
├── src/
│ ├── meu_projeto_web.gleam # Módulo principal
│ └── ...
└── test/
└── ...
2.2. Criando um servidor HTTP básico com a biblioteca mist
Mist é uma biblioteca HTTP minimalista para Gleam. Vamos criar um servidor simples:
// src/servidor.gleam
import gleam/io
import mist
pub fn main() {
let servidor = mist.new()
|> mist.port(8080)
|> mist.handle_request(handle_request)
|> mist.start
io.println("Servidor rodando em http://localhost:8080")
}
fn handle_request(requisicao: mist.Request) -> mist.Response {
mist.response(200)
|> mist.set_body("Olá do Gleam!")
}
2.3. Roteamento simples: tratando requisições GET e POST com padrões de URL
Vamos adicionar roteamento básico:
import mist
import gleam/string
fn handle_request(requisicao: mist.Request) -> mist.Response {
case requisicao.method, requisicao.path {
"GET", "/" -> mist.response(200) |> mist.set_body("Página inicial")
"GET", "/sobre" -> mist.response(200) |> mist.set_body("Sobre nós")
"POST", "/api/dados" -> processar_dados(requisicao)
_, _ -> mist.response(404) |> mist.set_body("Não encontrado")
}
}
fn processar_dados(requisicao: mist.Request) -> mist.Response {
// Lógica para processar dados POST
mist.response(201) |> mist.set_body("Dados recebidos")
}
3. Frameworks emergentes na BEAM para desenvolvimento web
3.1. Wisp: framework minimalista e funcional para Gleam
Wisp é um framework web que oferece middleware, roteamento e suporte a sessões:
import wisp
import wisp/router
pub fn main() {
let app = wisp.new()
|> wisp.use(middleware_log)
|> wisp.router(rotas)
|> wisp.start(8080)
}
fn rotas(router: router.Router) -> router.Router {
router
|> router.get("/", fn(_) { wisp.html("Home") })
|> router.get("/api/usuarios", listar_usuarios)
|> router.post("/api/usuarios", criar_usuario)
}
3.2. Lustre: abordagem baseada em componentes reativos (model-view-update) para front-end
Lustre traz o padrão Elm (Model-View-Update) para o navegador, compilando Gleam para JavaScript:
// Componente contador
pub fn init() -> Int { 0 }
pub fn view(modelo: Int) -> String {
"<div>
<p>Contagem: " <> int.to_string(modelo) <> "</p>
<button onclick='incrementar()'>+</button>
</div>"
}
pub fn update(modelo: Int, mensagem: String) -> Int {
case mensagem {
"incrementar" -> modelo + 1
_ -> modelo
}
}
3.3. Outros projetos promissores: Gig (servidor HTTP assíncrono) e Gleam HTTP
- Gig: servidor HTTP assíncrono focado em alta performance
- Gleam HTTP: biblioteca cliente/servidor HTTP de baixo nível
4. Construindo uma API RESTful com Gleam e Wisp
4.1. Definição de endpoints e validação de parâmetros com tipos customizados
import wisp
import wisp/request
import gleam/dynamic
pub type Usuario {
Usuario(id: Int, nome: String, email: String)
}
fn criar_usuario(requisicao: request.Request) -> wisp.Response {
let dados = request.body_json(requisicao)
case dados {
Ok(json) -> {
let nome = dynamic.field(json, "nome", dynamic.string)
let email = dynamic.field(json, "email", dynamic.string)
case nome, email {
Ok(n), Ok(e) -> salvar_usuario(Usuario(id: 0, nome: n, email: e))
_, _ -> wisp.json("{\"erro\": \"Campos inválidos\"}", 400)
}
}
Error(_) -> wisp.json("{\"erro\": \"JSON inválido\"}", 400)
}
}
4.2. Integração com banco de dados SQLite via gleam_sqlite
import gleam/sqlite
pub fn conectar_banco() -> Result(sqlite.Connection, String) {
sqlite.open("dados.db")
}
pub fn listar_usuarios(conexao: sqlite.Connection) -> List(Usuario) {
let consulta = sqlite.prepare(conexao, "SELECT id, nome, email FROM usuarios")
sqlite.fetch_all(consulta)
|> list.map(fn(linha) {
Usuario(
id: sqlite.column(linha, 0) |> int.parse |> result.unwrap(0),
nome: sqlite.column(linha, 1),
email: sqlite.column(linha, 2),
)
})
}
4.3. Tratamento de erros e respostas padronizadas (JSON, códigos HTTP)
pub type RespostaAPI(a) {
Sucesso(dados: a)
Erro(mensagem: String, codigo: Int)
}
pub fn resposta_json(resposta: RespostaAPI(a)) -> wisp.Response {
case resposta {
Sucesso(dados) -> wisp.json(dados, 200)
Erro(msg, codigo) -> wisp.json("{\"erro\": \"" <> msg <> "\"}", codigo)
}
}
5. Concorrência e estado compartilhado na web com BEAM
5.1. Modelo de atores no Gleam: criação de processos leves com gleam/otp
import gleam/otp/actor
pub type Mensagem {
Incrementar
ObterValor(remetente: actor.Address(Int))
}
pub fn contador_processo() -> actor.Behaviour(Mensagem, Int) {
actor.behaviour(
inicial: 0,
handle: fn(estado, mensagem) {
case mensagem {
Incrementar -> actor.Continuar(estado + 1)
ObterValor(remetente) -> {
actor.send(remetente, estado)
actor.Continuar(estado)
}
}
}
)
}
5.2. Gerenciamento de estado global com GenServers
import gleam/otp/gen_server
pub type Estado {
Estado(visitas: Int)
}
pub fn iniciar_contador() -> Result(gen_server.Server(Estado), String) {
gen_server.start_link(fn() { Estado(visitas: 0) }, [])
}
pub fn registrar_visita(servidor: gen_server.Server(Estado)) {
gen_server.call(servidor, fn(estado) {
#(Estado(visitas: estado.visitas + 1), estado.visitas + 1)
})
}
5.3. Supervisão e resiliência: árvores de supervisão para serviços web tolerantes a falhas
import gleam/otp/supervisor
pub fn iniciar_sistema() {
let criancas = [
supervisor.child(contador_processo, id: "contador_visitas"),
supervisor.child(servidor_http, id: "servidor_web"),
]
supervisor.start_link(
supervisor.strategy_one_for_one(),
criancas
)
}
6. Testes e boas práticas no ecossistema Gleam
6.1. Testes unitários e de integração com gleeunit
// test/test_usuarios.gleam
import gleeunit
import gleeunit/should
pub fn test_criar_usuario_valido() {
let resultado = criar_usuario("João", "joao@email.com")
resultado |> should.be_ok
}
pub fn test_email_invalido() {
let resultado = criar_usuario("Maria", "email-invalido")
resultado |> should.be_error
}
pub fn main() {
gleeunit.main()
}
6.2. Mocking de requisições HTTP e simulação de falhas
import gleam/http
pub fn test_resposta_api() {
let mock_resposta = http.Response(
status: 200,
headers: [],
body: "{\"mensagem\": \"OK\"}"
)
processar_resposta(mock_resposta) |> should.equal("OK")
}
6.3. Padrões de projeto: separação de lógica de negócio, middlewares e configuração
Organize seu projeto em camadas:
src/
├── api/ # Rotas e controladores
│ ├── usuarios.gleam
│ └── produtos.gleam
├── dominio/ # Lógica de negócio
│ ├── entidades.gleam
│ └── servicos.gleam
├── infra/ # Banco de dados, cache
│ ├── repositorio.gleam
│ └── cache.gleam
└── config/ # Configurações
└── configuracao.gleam
7. Deploy e desempenho de aplicações Gleam
7.1. Compilação para Erlang e execução em clusters BEAM
# Compilar para Erlang
gleam build --target erlang
# Executar em modo distribuído
erl -sname no1@localhost -setcookie segredo -run meu_app start
erl -sname no2@localhost -setcookie segredo -run meu_app start
7.2. Otimizações: uso de ETS para cache, pool de conexões
import gleam/ets
pub fn criar_cache() -> ets.Table {
ets.new("cache_web", [ets.public, ets.named_table])
}
pub fn armazenar_cache(tabela: ets.Table, chave: String, valor: String) {
ets.insert(tabela, #(chave, valor))
}
7.3. Exemplos práticos: deploy em servidores leves com Docker
FROM ghcr.io/gleam-lang/gleam:latest AS builder
WORKDIR /app
COPY . .
RUN gleam build --target erlang
FROM erlang:26-alpine
WORKDIR /app
COPY --from=builder /app/build/prod/rel .
EXPOSE 8080
CMD ["bin/meu_app", "start"]
Referências
- Documentação oficial do Gleam — Guia completo da linguagem, instalação e referência da biblioteca padrão
- Mist - Servidor HTTP para Gleam — Documentação oficial da biblioteca HTTP minimalista para Gleam
- Wisp - Framework web para Gleam — Documentação do framework web com middleware, roteamento e sessões
- Lustre - Framework reativo front-end — Documentação do framework Model-View-Update para aplicações web no navegador
- Gleam SQLite — Biblioteca para integração com banco de dados SQLite em Gleam
- Gleam OTP — Documentação dos módulos OTP para concorrência, GenServers e supervisão
- Gleeunit - Framework de testes — Documentação do framework de testes unitários nativo do Gleam
- Gigalixir - Deploy de aplicações BEAM — Plataforma de deploy especializada em aplicações Erlang/Elixir/Gleam