Ir al contenido

Routing

Los routers agrupan endpoints bajo prefijos de URL y aplican middleware compartido. Los endpoints definen manejadores HTTP.

flowchart TB
S[http.service<br/>:8080] --> R1[http.router<br/>/api]
S --> R2[http.router<br/>/admin]
S --> ST[http.static<br/>/]
R1 --> E1[GET /users]
R1 --> E2[POST /users]
R1 --> E3["GET /users/{id}"]
R2 --> E4[GET /stats]
R2 --> E5[POST /config]

Las entradas referencian padres vía metadatos:

  • Routers: meta.server: app:gateway
  • Endpoints: meta.router: app:api
- name: api
kind: http.router
meta:
server: gateway
prefix: /api/v1
middleware:
- cors
- compress
options:
cors.allow.origins: "*"
post_middleware:
- endpoint_firewall
CampoTipoDescripción
meta.serverID de RegistroServidor HTTP padre
prefixstringPrefijo de URL para todas las rutas
middleware[]stringMiddleware pre-match
optionsmapOpciones de middleware
post_middleware[]stringMiddleware post-match
post_optionsmapOpciones de middleware post-match
- name: get_user
kind: http.endpoint
meta:
router: api
method: GET
path: /users/{id}
func: app.users:get_user
CampoTipoDescripción
meta.routerID de RegistroRouter padre
methodstringMétodo HTTP (GET, POST, PUT, DELETE, PATCH, HEAD)
pathstringPatrón de ruta URL (comienza con /)
funcID de RegistroFunción handler

Use sintaxis {param} para parámetros de URL:

- name: get_post
kind: http.endpoint
meta:
router: api
method: GET
path: /users/{user_id}/posts/{post_id}
func: get_user_post

Acceso en handler:

local http = require("http")
local function handler()
local req = http.request()
local user_id = req:param("user_id")
local post_id = req:param("post_id")
-- ...
end

Capture segmentos de ruta restantes con {param...}:

- name: serve_files
kind: http.endpoint
meta:
router: api
method: GET
path: /files/{filepath...}
func: serve_file
-- Solicitud: GET /api/v1/files/docs/guides/readme.md
local file_path = req:param("filepath") -- "docs/guides/readme.md"

El comodín debe ser el último segmento en la ruta.

Los handlers de endpoint usan el módulo http para acceder a objetos de solicitud y respuesta. Ver Módulo HTTP para la API completa.

local http = require("http")
local json = require("json")
local function handler()
local req = http.request()
local res = http.response()
local user_id = req:param("id")
local user = get_user(user_id)
res:status(200)
res:write(json.encode(user))
end
return { handler = handler }

Las opciones de middleware usan notación de punto con el nombre del middleware como prefijo:

middleware:
- cors
- ratelimit
- token_auth
options:
cors.allow.origins: "https://app.example.com"
cors.allow.methods: "GET,POST,PUT,DELETE"
ratelimit.requests: "100"
ratelimit.window: "1m"
token_auth.store: "app:tokens"
token_auth.header.name: "Authorization"

El middleware post-match usa post_options:

post_middleware:
- endpoint_firewall
post_options:
endpoint_firewall.default_policy: "deny"

Pre-match (middleware) se ejecuta antes del matching de ruta:

  • CORS (maneja preflight OPTIONS)
  • Compresión
  • Rate limiting
  • Detección de IP real
  • Autenticación de token (enriquecimiento de contexto)

Post-match (post_middleware) se ejecuta después de que la ruta es matcheada:

  • Firewall de endpoint (necesita info de ruta para autorización)
  • Firewall de recurso
  • WebSocket relay
middleware: # Pre-match: todas las solicitudes a este router
- cors
- compress
- token_auth # Enriquece contexto con actor/scope
post_middleware: # Post-match: solo rutas matcheadas
- endpoint_firewall # Usa actor de token_auth
La autenticación de token puede ser pre-match porque solo enriquece contexto: no bloquea solicitudes. La autorización ocurre en middleware post-match como endpoint_firewall que usa el actor establecido por token_auth.
version: "1.0"
namespace: app
entries:
# Servidor
- name: gateway
kind: http.service
addr: ":8080"
lifecycle:
auto_start: true
# Router de API
- name: api
kind: http.router
meta:
server: gateway
prefix: /api/v1
middleware:
- cors
- compress
- ratelimit
options:
cors.allow.origins: "https://app.example.com"
ratelimit.requests: "100"
ratelimit.window: "1m"
# Función handler
- name: get_users
kind: function.lua
source: file://handlers/users.lua
method: list
modules:
- http
- json
- sql
# Endpoints
- name: list_users
kind: http.endpoint
meta:
router: api
method: GET
path: /users
func: get_users
- name: get_user
kind: http.endpoint
meta:
router: api
method: GET
path: /users/{id}
func: app:get_user_by_id
- name: create_user
kind: http.endpoint
meta:
router: api
method: POST
path: /users
func: app:create_user

Patrón común con autenticación:

entries:
# Rutas públicas (sin auth)
- name: public
kind: http.router
meta:
server: gateway
prefix: /api/public
middleware:
- cors
# Rutas protegidas
- name: protected
kind: http.router
meta:
server: gateway
prefix: /api
middleware:
- cors
- token_auth
options:
token_store: app:tokens
post_middleware:
- endpoint_firewall