RRuna

Route Context

Read requests, write responses, and access application capabilities

route.Context is the request context for HTTP handlers. It wraps http.Request, the response writer, route parameters, config, and request-level Scope.

Every HTTP request gets a new route.Context. Do not store it in a global variable or keep using it after the request has ended.

Basic usage

route.Default().Get("/users/{id}", func(ctx *route.Context) error {
    id := ctx.Param[string]("id")
    return ctx.JSON(runa.Map{"id": id})
})

This reads id from /users/{id} and returns JSON.

Read request data

route.Default().Get("/search/{category}", func(ctx *route.Context) error {
    category := ctx.Param[string]("category")
    keyword := ctx.Query[string]("keyword")
    page := ctx.Query[int]("page", 1)
    userAgent := ctx.Request().UserAgent()

    return ctx.JSON(runa.Map{
        "category": category,
        "keyword": keyword,
        "page": page,
        "ua": userAgent,
    })
})

Common methods:

Method Description
Param[T](name, fallback...) Reads and casts a path parameter
Query[T](name, fallback...) Reads and casts a query parameter
Header[T](name, fallback...) Reads and casts a request header
Cookie[T](name, fallback...) Reads and casts a cookie
Form[T](name, fallback...) Reads and casts a form value
Meta[T](key, fallback...) Reads and casts current route metadata
Input[T]() Binds and validates request input into T
Service[T](name...) Reads a service injected into the route context
Request() Returns the raw *http.Request
Response() Returns the raw http.ResponseWriter
Context() Returns the request context.Context
Body() Reads the request body and restores it for later logic

Write responses

return ctx.Text("ok")
return ctx.HTML("<h1>ok</h1>")
return ctx.JSON(runa.Map{"ok": true})
return ctx.Blob("application/octet-stream", body)

Set a status code:

return ctx.Status(201).JSON(runa.Map{"created": true})

Read config

route.Default().Get("/config", func(ctx *route.Context) error {
    name := ctx.Config("app").Get[string]("name")
    return ctx.Text(name)
})

ctx.Config("app") reads the config scope backed by config/app.toml.

Read capabilities from Context

Capability objects are usually accessed through their package Default(), such as cache.Default(), database.Default(), and queue.Default().

route.Default().Get("/cache", func(ctx *route.Context) error {
    store := cache.Default().MustOf[string]("default")
    value, ok, err := store.Get(ctx.Context(), "hello")
    if err != nil {
        return err
    }
    if !ok {
        return ctx.Status(404).Text("cache not found")
    }
    return ctx.Text(value)
})

ctx.Context() is the current request’s standard library context. Pass it to databases, caches, queues, and external calls.

Request-level data

Request-level objects are useful for trace IDs, the current user, permission context, and other temporary data. Middleware can write first, and later handlers can read.

If the object is shared across requests, do not put it in route.Context. Put it in DI, cache, database, or a business service.

Error responses

return ctx.Error(404, "user not found")

For more complex errors, use the errs toolkit so error codes and params stay consistent.

return errs.New("user not found", errs.Code("user.not_found"))

Common mistakes

Passing route.Context to a background goroutine

After the request ends, route.Context should not be used. If you need async work, copy the required data and pass it to a queue or background task.

Forgetting ctx.Context()

When calling databases, caches, or HTTP clients, prefer ctx.Context() so downstream work can stop when the request is canceled.

Edit this page