Create an Adapter
Build and ship your own Kizuna adapter for any HTTP runtime using defineAdapter from kizunajs/adapter.
kizunajs/adapter exposes defineAdapter so third parties can build and ship their own adapters independently. Kizuna ships Express, Fastify, Hono, and Next.js.
Whether an adapter goes first-party comes down to adoption, not age. If a framework picks up real usage, we will very likely add it. What we will not take on is a framework a handful of people use, since we maintain everything we merge. The adapter API is public, so you can build and publish your own today.
Overview
An adapter translates between a native HTTP runtime (Bun, Cloudflare Workers, Deno, etc.) and Kizuna's handler pipeline. You provide three things:
buildHandlerContextbuilds the context object your handlers receive alongside validated inputsrespondtranslates anAdapterResultto a native responseonError(optional) intercepts unhandled handler errors
defineAdapter
Minimal example (fetch-based runtime)
AdapterDefinition
| Field | Description |
|---|---|
buildHandlerContext | Returns the context object each handler receives alongside params, query, body, headers. |
respond | Translates an AdapterResult to a native response. Always handle kind: 'raw-response' first, as it carries a pre-built native response from onError. |
onError | Called on unhandled handler errors. Return an AdapterResult to override the default 500, or return void to let it pass through. |
matcher | Custom route matcher. Defaults to Kizuna's built-in path matcher. |
AdapterRequest
Use kind: 'core-match' for catch-all routing (one handler handles all paths). Use kind: 'pre-resolved' for per-route registration (Express-style, where the framework has already matched the route).
AdapterResult
respond receives one of these from the pipeline:
kind | When |
|---|---|
success | Handler returned a valid response |
not-found | No route matched the path |
method-not-allowed | Path matched but method is not in the routes |
validation-failed | params, query, headers, or body failed schema validation |
handler-error | Handler threw an unhandled error |
raw-response | onError returned an override, so cast result.response back to NativeResponse |
Helpers
renderJsonResult
Translates any AdapterResult (except raw-response) to { status, headers, body } using Kizuna's defaults, such as 405 with an Allow header and validation errors as Problem Details (detail plus an errors array).
Pass the request's method as the fourth argument when your adapter writes the wire bytes itself: a HEAD request then keeps GET's status and headers, gains a Content-Length, and loses the content (RFC 9110 §9.3.2). Leave it unset when the framework discards HEAD content itself, as Express, Fastify, and Hono do.
A success result on a status declared with stream renders with body undefined and a stream function in its place. Check stream before body, hand it the signal that fires when the client goes away, and write the ReadableStream it returns. encodeStreamBody(result, { signal }) does the same for an adapter that renders results itself.
parseFetchBody
Content-type-aware body parsing for fetch-based runtimes (Request / Response API). Handles application/json, multipart/form-data, and application/x-www-form-urlencoded.
entriesToObject
Converts a URLSearchParams or FormData to an object. A repeated key, ?ids=1&ids=2, becomes a list of every value.
headersToObject
Converts a Headers instance to Record<string, string>.