Beta documentation. This is an early preview — content is still in active development. Feedback helps shape the final release. Share your thoughts or join the discussion.

Routing

Map URLs to handler functions. Wapka supports all standard HTTP verbs:

On this page

Route methods

Map URLs to handler functions. Wapka supports all standard HTTP verbs:

local app = framework()

app:get("/users", handler)       -- read
app:post("/users", handler)      -- create
app:put("/users/:id", handler)   -- full update
app:patch("/users/:id", handler)  -- partial update
app:delete("/users/:id", handler) -- remove
app:head("/users", handler)      -- headers only (also auto-matches GET)
app:any("/webhook", handler)     -- any method

Path parameters

Capture dynamic URL segments with :name:

-- /blog/hello-world  →  ctx.params.slug = "hello-world"
app:get("/blog/:slug", function(ctx)
    local post = api.posts.list({ search = ctx.params.slug })
    return ctx:render("post", { post = post.items[1] })
end)

-- /blog/2026/05/launch-day  →  ctx.params.year, .month, .slug
app:get("/blog/:year/:month/:slug", function(ctx)
    return {
        year = ctx.params.year,
        month = ctx.params.month,
        slug = ctx.params.slug
    }
end)

Wildcard routes

Capture everything after a path segment with *:

-- /files/docs/report.pdf  →  ctx.params.path = "docs/report.pdf"
app:get("/files/*path", function(ctx)
    return { file = ctx.params.path }
end)

Route groups

Group routes under a common prefix — keeps large apps organized:

app:group("/api/v1", function()
    app:get("/status", statusHandler)     -- → /api/v1/status
    app:get("/users", listUsers)          -- → /api/v1/users
    app:post("/users", createUser)        -- → /api/v1/users
end)

app:group("/admin", function()
    app:get("/dashboard", adminHome, { middleware = "admin" })
    app:get("/users", adminUsers, { middleware = { "auth", "admin" } })
end)

Named routes + URL generation

Name a route so you can generate URLs from code — never hardcode URLs:

app:get("/blog/:slug", postHandler, { name = "blog.post" })

-- Generate URL anywhere:
local url = app:url("blog.post", { slug = "hello-world" })
-- → "/blog/hello-world"

Use this in templates, redirects, emails — update the route definition and all links follow.

Route options

The third argument to any route method is an options table:

app:post("/webhook/stripe", stripeHandler, {
    name = "stripe.webhook",          -- named route
    middleware = { "json" },          -- route-level middleware
    csrf = false,                     -- disable CSRF for this route
})
Option Type Description
name string Named route for app:url()
middleware string or table Middleware for this specific route
csrf boolean Set false to skip CSRF check (webhooks)

Error responses

Wapka handles missing routes automatically:

  • 404 — No route matches the URL
  • 405 — URL matches a route but with the wrong HTTP method

Your app doesn't need a catch-all unless you want custom 404 pages.

Next: Request & Environment — read incoming data.

Previous Globals Reference Next Request & Environment