Direct Route Params Injection¶
Verified status as of March 28, 2026. Runtime note: FastFN auto-installs function-local dependencies from
requirements.txt/package.json; host runtimes are required infastfn dev --native, whilefastfn devdepends on a running Docker daemon. FastFN automatically injects route parameters as direct function arguments. Instead of digging intoevent.params.id, you simply declareidin your handler signature and it arrives ready to use.
Before and After¶
Before (manual extraction):
def handler(event):
id = event.get("params", {}).get("id", "")
slug = event.get("params", {}).get("slug", "")
After (direct injection):
How It Works¶
FastFN inspects your handler's signature at call time and injects matching route params automatically.
| Runtime | Mechanism | Handler Signature |
|---|---|---|
| Python | inspect.signature → kwargs injection |
def handler(event, id): |
| Node.js | Second arg when handler.length > 1 |
async (event, { id }) => |
| PHP | ReflectionFunction → second arg |
function handler($event, $params) |
| Lua | Always passed as second arg | function handler(event, params) |
| Go | Params merged into event map | event["id"].(string) |
| Rust | Params merged into event value | event["id"].as_str() |
100% Backward Compatible
Existing handler(event) signatures continue to work unchanged. Params are only injected when the handler declares extra parameters.
Param Types¶
[id] — Single Dynamic Param¶
File: products/[id]/get.py → Route: GET /products/:id
package main
import ("encoding/json"; "strconv")
func handler(event map[string]interface{}) interface{} {
idStr, _ := event["id"].(string) // merged from params
id, _ := strconv.Atoi(idStr)
body, _ := json.Marshal(map[string]interface{}{"id": id, "name": "Widget"})
return map[string]interface{}{
"status": 200, "headers": map[string]string{"Content-Type": "application/json"},
"body": string(body),
}
}
[slug] — Named Param¶
File: posts/[slug]/get.py → Route: GET /posts/:slug
[category]/[slug] — Multiple Params¶
File: posts/[category]/[slug]/get.py → Route: GET /posts/:category/:slug
[...path] — Catch-All Wildcard¶
File: files/[...path]/get.py → Route: GET /files/*
The entire remaining path after /files/ is captured as a single string.
local cjson = require("cjson")
local function handler(event, params)
local path = params.path or ""
local segments = {}
if path ~= "" then
for seg in path:gmatch("[^/]+") do
segments[#segments + 1] = seg
end
end
return {
status = 200,
body = cjson.encode({ path = path, segments = segments, depth = #segments }),
}
end
return handler
Complete CRUD Example¶
Here's a full REST API using method-specific files with param injection:
products/
get.py GET /products — list all
post.py POST /products — create
[id]/
get.py GET /products/:id — read one
put.py PUT /products/:id — update
delete.py DELETE /products/:id — delete
Each handler is clean and focused:
# products/get.py — list all
def handler(event):
return {"status": 200, "body": [{"id": 1, "name": "Widget"}]}
# products/post.py — create
def handler(event):
import json
body = json.loads(event.get("body", "{}"))
return {"status": 201, "body": {"id": 1, "name": body.get("name")}}
# products/[id]/get.py — read one
def handler(event, id):
return {"status": 200, "body": {"id": int(id), "name": "Widget"}}
# products/[id]/put.py — update
def handler(event, id):
import json
body = json.loads(event.get("body", "{}"))
return {"status": 200, "body": {"id": int(id), "name": body.get("name")}}
# products/[id]/delete.py — delete
def handler(event, id):
return {"status": 200, "body": {"id": int(id), "deleted": True}}
Test with curl¶
fastfn dev examples/functions/rest-api-methods
# List
curl http://127.0.0.1:8080/products
# Create
curl -X POST http://127.0.0.1:8080/products \
-H "Content-Type: application/json" -d '{"name":"Widget"}'
# Read (id=42 injected directly)
curl http://127.0.0.1:8080/products/42
# Update
curl -X PUT http://127.0.0.1:8080/products/42 \
-H "Content-Type: application/json" -d '{"name":"Updated"}'
# Delete
curl -X DELETE http://127.0.0.1:8080/products/42
# Slug param
curl http://127.0.0.1:8080/posts/hello-world
# Multi-param
curl http://127.0.0.1:8080/posts/tech/hello-world
# Wildcard catch-all
curl http://127.0.0.1:8080/files/docs/2024/report.pdf
Summary¶
| Pattern | File Example | Python | Node.js |
|---|---|---|---|
[id] |
[id]/get.py |
def handler(event, id): |
async (event, { id }) => |
[slug] |
[slug]/get.py |
def handler(event, slug): |
async (event, { slug }) => |
| Multi | [cat]/[slug]/get.py |
def handler(event, category, slug): |
async (event, { category, slug }) => |
| Catch-all | [...path]/get.py |
def handler(event, path): |
async (event, { path }) => |
See the full working examples in examples/functions/rest-api-methods/.
Flow Diagram¶
flowchart LR
A["Client request"] --> B["Route discovery"]
B --> C["Policy and method validation"]
C --> D["Runtime handler execution"]
D --> E["HTTP response + OpenAPI parity"]
Objective¶
Clear scope, expected outcome, and who should use this page.
Prerequisites¶
- FastFN CLI available
- Runtime dependencies by mode verified (Docker for
fastfn dev, OpenResty+runtimes forfastfn dev --native)
Validation Checklist¶
- Command examples execute with expected status codes
- Routes appear in OpenAPI where applicable
- References at the end are reachable
Troubleshooting¶
- If runtime is down, verify host dependencies and health endpoint
- If routes are missing, re-run discovery and check folder layout