Pular para o conteúdo

Middleware

CORS, log, autenticação e limite de taxa — e por que a ordem importa.

A regra#

Middleware roda antes de toda rota. Se devolve uma resposta, a cadeia para ali. Se devolve void, o pedido segue — e o que ele guardou em req["state"] chega na rota.

dataforge
server api on 8080:
    middleware Kiln.rate_limit(60, 60)
    middleware Kiln.logger()
    middleware Kiln.auth(conferir_token)

    route GET "/eu":
        respond json {"usuario": req["state"]["user"]}

Os prontos#

MiddlewareFaz
Kiln.cors(origens)responde o preflight OPTIONS e libera origens
Kiln.logger()uma linha por pedido no terminal
Kiln.rate_limit(max, janela)429 + Retry-After ao estourar
Kiln.auth(verificador)401 sem credencial; põe o usuário em state
Kiln.guard(condicao, status, msg)middleware a partir de qualquer condição

A ordem importa#

dataforge
// certo
middleware Kiln.rate_limit(60, 60)
middleware Kiln.auth(conferir)

// errado
middleware Kiln.auth(conferir)
middleware Kiln.rate_limit(60, 60)

Na ordem errada, um pedido barrado pelo auth nunca chega a ser contado — e quem está martelando a porta com credenciais inválidas é justamente quem você quer limitar. O limite vem primeiro, sempre.

Autenticação é sua#

dataforge
action conferir(token):
    linhas := DB.query(banco,
        "SELECT usuario FROM sessoes WHERE token = ?", [token])
    yield linhas[0]["usuario"] given len(linhas) bigger 0 otherwise void

middleware Kiln.auth(conferir)

Kiln.auth cuida do protocolo: lê o Authorization, devolve 401 com WWW-Authenticate, e põe o resultado em req["state"]["user"]. Quem decide se o token vale é a sua ação — o Kiln não escolhe seu banco nem seu formato de token.

Middleware próprio#

dataforge
action so_de_dia(req):
    hora := Time.now().hour
    given hora smaller 8 or hora bigger_eq 18:
        yield Kiln.json({"erro": "fora do horário"}, 503)
    yield void        // void deixa passar

middleware so_de_dia

Devolva algo só quando for para cortar o pedido. Um middleware que devolve um valor sem querer interrompe a cadeia e a rota nunca roda — e nada no terminal explica por quê.

Depois da resposta#

dataforge
Kiln.after(app, lambda req, resp => Kiln.header(
    resp, "X-Powered-By", "DataForge"))

Roda com a resposta pronta, para carimbar cabeçalhos ou medir. Um erro aqui é engolido: nada pode derrubar uma resposta que já está montada.

CORS#

dataforge
middleware Kiln.cors()                       // libera tudo
middleware Kiln.cors("https://meusite.com")  // uma origem

O OPTIONS é respondido no middleware e nunca chega na rota — por isso você não precisa registrar uma rota OPTIONS para cada caminho.

Limite de taxa: a letra miúda#

A contagem é por processo e em memória: com vários processos, cada um tem a sua, e o limite efetivo é o número de processos vezes o teto. Serve muito bem para uma aplicação de um processo e para conter abuso acidental; para um limite rígido, use um contador compartilhado.