Skip to content
Request Context

KosmoJS extends the standard Hono/H3/Koa context with three additions: unified bodyparser and metaparser APIs, and ctx.validated for type-safe access to validated request data.

Unified Bodyparser ​

ctx.bodyparser works the same regardless of framework:

ts
await ctx.bodyparser.json()   // JSON request body
await ctx.bodyparser.form()   // URL-encoded or multipart form
await ctx.bodyparser.raw()    // raw body buffer

Results are cached - calling the same parser multiple times doesn't re-parse the request.

In practice you rarely call this directly. Define a validation schema in your handler and the appropriate parser runs automatically, placing the result in ctx.validated.

Unified Metaparser ​

ctx.metaparser does the same for request metadata:

ts
ctx.metaparser.params()    // route params, normalized
ctx.metaparser.query()     // query parameters, normalized
ctx.metaparser.headers()   // headers, as a plain object
ctx.metaparser.cookies()   // parsed cookies

These are synchronous - there is nothing to await - and cached the same way.

params() and query() hand back normalized values rather than raw strings: splat params are split into arrays, and values are coerced to match your declared types - numbers for params, numbers and booleans for query. headers() and cookies() are plain parses.


Both ctx.metaparser and ctx.bodyparser are rarely used in handlers directly. They are most useful in edge middleware and in a custom validator. where ctx.validated.* is not filled yet.

They are not there in api/app.ts, which runs before the context is extended.

Validated Data Access ​

ctx.validated holds the validated, typed result for each target you defined:

ts
export default defineRoute<"users">(({ POST }) => [
  POST<{
    json: Payload<CreateUser>,
    query: { limit: number },
    headers: { "x-api-key": string },
  }>(async (ctx) => {
    const user = ctx.validated.json;      // validated JSON body
    const limit = ctx.validated.query;    // validated query params
    const apiKey = ctx.validated.headers; // validated headers
  }),
]);

Route Parameters ​

Validated params are available at ctx.validated.params, typed according to your refinements:

api/users/[id]/index.ts
ts
export default defineRoute<"users/[id]", [number]>(({ GET, POST }) => [
  GET<{
    query: { page: string; filter?: string },
  }>(async (ctx) => {
    const { id } = ctx.validated.params;    // number
    const { page, filter } = ctx.validated.query;
  }),

  POST<{
    json: Payload<User>,
  }>(async (ctx) => {
    const { id } = ctx.validated.params;    // number
    const user = ctx.validated.json;
  }),
]);

ctx.metaparser.params() gives you the same normalized values before validation runs - useful in edge middleware, where ctx.validated is still empty.

The underlying raw params still exist if you need them:

  • Hono - ctx.req.param()
  • H3 - event.context.params
  • Koa - ctx.params

Released under the MIT License.