Routing
Routing
Section titled “Routing”Routers group endpoints under URL prefixes and apply shared middleware. Endpoints define HTTP handlers.
Architecture
Section titled “Architecture”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]Entries reference parents via metadata:
- Routers:
meta.server: app:gateway - Endpoints:
meta.router: app:api
Router Configuration
Section titled “Router Configuration”- name: api kind: http.router meta: server: gateway prefix: /api/v1 middleware: - cors - compress options: cors.allow.origins: "*" post_middleware: - endpoint_firewall| Field | Type | Description |
|---|---|---|
meta.server | Registry ID | Parent HTTP server |
prefix | string | URL prefix for all routes |
middleware | []string | Pre-match middleware |
options | map | Middleware options |
post_middleware | []string | Post-match middleware |
post_options | map | Post-match middleware options |
Endpoint Configuration
Section titled “Endpoint Configuration”- name: get_user kind: http.endpoint meta: router: api method: GET path: /users/{id} func: app.users:get_user| Field | Type | Description |
|---|---|---|
meta.router | Registry ID | Parent router |
method | string | HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE |
path | string | URL path pattern (starts with /) |
func | Registry ID | Handler function |
Path Parameters
Section titled “Path Parameters”Use {param} syntax for URL parameters:
- name: get_post kind: http.endpoint meta: router: api method: GET path: /users/{user_id}/posts/{post_id} func: get_user_postAccess in 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")
-- ...endWildcard Paths
Section titled “Wildcard Paths”Capture remaining path segments with {param...}:
- name: serve_files kind: http.endpoint meta: router: api method: GET path: /files/{filepath...} func: serve_fileThe wildcard matches the remaining segments for routing purposes, so a request like GET /api/v1/files/docs/guides/readme.md is matched and dispatched to the handler. The captured tail itself is not currently retrievable via req:param.
The wildcard must be the last segment in the path.
Handler Functions
Section titled “Handler Functions”Endpoint handlers use the http module to access request and response objects. See HTTP Module for the complete API.
local http = require("http")
local function handler() local req = http.request() local res = http.response()
local user_id = req:param("id") local user = get_user(user_id)
res:set_status(http.STATUS.OK) res:write_json(user)end
return { handler = handler }Middleware Options
Section titled “Middleware Options”Middleware options use dot notation with the middleware name as prefix:
middleware: - cors - ratelimit - token_authoptions: 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"Post-match middleware uses post_options:
post_middleware: - endpoint_firewallpost_options: endpoint_firewall.action: "access"Pre-Match vs Post-Match Middleware
Section titled “Pre-Match vs Post-Match Middleware”Pre-match (middleware) runs before route matching:
- CORS (handles OPTIONS preflight)
- Compression
- Rate limiting
- Real IP detection
- Token authentication (context enrichment)
Post-match (post_middleware) runs after route is matched:
- Endpoint firewall (needs route info for authorization)
- Resource firewall
- WebSocket relay
middleware: # Pre-match: all requests to this router - cors - compress - token_auth # Enriches context with actor/scope
post_middleware: # Post-match: matched routes only - endpoint_firewall # Uses actor from token_authendpoint_firewall which uses the actor set by token_auth.
Complete Example
Section titled “Complete Example”version: "1.0"namespace: app
entries: # Server - name: gateway kind: http.service addr: ":8080" lifecycle: auto_start: true
# API Router - 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"
# Handler function - 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_userProtected Routes
Section titled “Protected Routes”Common pattern with authentication:
entries: # Public routes (no auth) - name: public kind: http.router meta: server: gateway prefix: /api/public middleware: - cors
# Protected routes - name: protected kind: http.router meta: server: gateway prefix: /api middleware: - cors - token_auth options: token_auth.store: app:tokens post_middleware: - endpoint_firewallSee Also
Section titled “See Also”- Server - HTTP server configuration
- Static Files - Static file serving
- Middleware - Available middleware
- HTTP Module - Lua HTTP API