Context & Requests
Every route handler receives a context object
containing request data, response helpers, and shared state via
locals.
Context Structure
ctx = {
request = { -- Incoming request data
method = "GET", -- HTTP method
path = "/users", -- Request path
query = {}, -- Query parameters
headers = {}, -- Request headers
body = {} -- Parsed body data
},
params = {}, -- Route parameters (e.g., :id)
locals = {}, -- Shared state (middleware storage)
response = { -- Response helpers
setHeader = function(name, value),
setStatus = function(code)
}
}
Request Object
Access incoming request data via ctx.request:
Basic Properties
app:get("/example", function(ctx)
-- HTTP method (GET, POST, PUT, DELETE, etc.)
local method = ctx.request.method
-- Full request path
local path = ctx.request.path
-- Query string parameters
local search = ctx.request.query.search
local page = ctx.request.query.page or "1"
return Nixi.p(nil, "Method: " .. method .. ", Path: " .. path)
end)
Headers
app:get("/api/user", function(ctx)
-- Access specific header
local auth = ctx.request.headers["Authorization"]
local content_type = ctx.request.headers["Content-Type"]
local user_agent = ctx.request.headers["User-Agent"]
-- Check for API key
if not auth then
return Nixi.error(401, "Missing authorization")
end
return Nixi.json({ authorized = true })
end)
Body Parsing
app:post("/form", function(ctx)
-- Access parsed form data
local name = ctx.request.body.name
local email = ctx.request.body.email
-- For multipart forms
local file = ctx.request.body.file
if file then
local filename = file.filename
local content = file.content
end
return Nixi.p(nil, "Hello " .. name)
end)
app:post("/api/data", function(ctx)
-- JSON body is auto-parsed
local data = ctx.request.body
local username = data.username
local settings = data.settings
return Nixi.json({ received = true })
end)
Route Parameters
-- Define route with parameters
app:get("/users/:id/posts/:post_id", function(ctx)
local user_id = ctx.params.id
local post_id = ctx.params.post_id
return Nixi.p(nil, "User " .. user_id .. ", Post " .. post_id)
end)
Response Object
Modify the response using ctx.response:
app:get("/custom", function(ctx)
-- Set custom headers
ctx.response:setHeader("X-Custom-Header", "value")
ctx.response:setHeader("Cache-Control", "no-cache")
-- Set status code
ctx.response:setStatus(201)
return "Created!"
end)
Locals Storage
Use ctx.locals to share data between middleware and route
handlers:
Setting Locals in Middleware
-- Authentication middleware
local function authenticate(ctx)
local token = ctx.request.headers["Authorization"]
if token then
-- Validate token and set user info
local user = validateToken(token)
ctx.locals.user = user
ctx.locals.isAuthenticated = true
else
ctx.locals.isAuthenticated = false
end
end
-- Apply middleware
app:use(authenticate)
Accessing Locals in Routes
app:get("/profile", function(ctx)
if not ctx.locals.isAuthenticated then
return Nixi.redirect("/login")
end
local user = ctx.locals.user
return Nixi.p(nil, "Welcome, " .. user.name)
end)
-- Protected API endpoint
app:get("/api/data", function(ctx)
if not ctx.locals.user then
return Nixi.error(403, "Access denied")
end
return Nixi.json({
user = ctx.locals.user.name,
data = getData(ctx.locals.user.id)
})
end)
Common Locals Patterns
| Use Case | Locals Key | Set By |
|---|---|---|
| User session | ctx.locals.user |
Auth middleware |
| Database connection | ctx.locals.db |
DB middleware |
| Request timing | ctx.locals.startTime |
Timing middleware |
| Flash messages | ctx.locals.flash |
Session middleware |
Example: Full Middleware Chain
-- Request timing middleware
local function timing(ctx)
ctx.locals.startTime = os.time()
end
-- Authentication middleware
local function auth(ctx)
local token = ctx.request.headers["Authorization"]
if token then
ctx.locals.user = decodeJWT(token)
ctx.locals.isAuthenticated = true
end
end
-- Logger middleware
local function logger(ctx)
local elapsed = os.time() - ctx.locals.startTime
print(string.format("[%s] %s - %dms",
ctx.request.method,
ctx.request.path,
elapsed * 1000))
end
-- Apply middleware (order matters!)
app:use(timing)
app:use(auth)
-- Log after request
app:get("/slow", function(ctx)
-- ... route handler ...
end)
Context in Components
Pass context to child components:
app:get("/dashboard", function(ctx)
return Nixi.div(
nil,
Nixi.h1(nil, "Dashboard"),
Nixi.Component("user_panel", {
user = ctx.locals.user,
ctx = ctx
})
)
end)