Core Primitives β
bunway decorates Bunβs Fetch primitives with lightweight helpers. Understanding these building blocks makes it easier to compose middleware and handlers.
WayContext β
Every handler receives a WayContext object:
app.use(async (ctx, next) => {
console.log(ctx.req.method, ctx.req.path);
await next();
});ctx.reqβ {@link WayRequest}: wrapper around BunβsRequestwithparams,query,locals, body parsing helpers, etc.ctx.resβ {@link WayResponse}: fluent builder for returning JSON/text/any payloads while still exposing the underlyingResponse.
WayRequest β
app.get("/users/:id", async (ctx) => {
const id = ctx.req.param("id");
const search = ctx.req.query.get("status");
const payload = await ctx.req.parseBody();
// Store data for downstream middleware/handlers
ctx.req.locals.user = { id, search, payload };
return ctx.res.ok({ id, search, payload });
});Key helpers β
params/param()β Express-style route parameters.queryβURLSearchParamsinstance for query string access.localsβ shared mutable state across middleware.bodyβ cached payload filled by the auto parser; perfect when you just need the data.parseBody()β respects global + per-request overrides and returns the cached payload.applyBodyParserOverrides()β tweak body parsing on the fly.rawBody()/rawText()β lazy access to the request body (cached).
Locals
Use ctx.req.locals as a per-request scratchpad. Itβs perfect for sharing deserialized users, permissions, or tracing IDs between middleware and handlers.
Fun fact β The Bun way
ctx.req.bodyParseError stores details when parsing fails (status + message). Check it before running expensive logic to send friendlier responses.
WayResponse β
app.post("/sessions", async (ctx) => {
const session = await createSession(ctx.req);
return ctx.res
.status(201)
.header("Set-Cookie", `session=${session.id}; HttpOnly; Path=/`)
.json({ id: session.id });
});Key helpers β
status(code)β chainable status setter.header(name, value)β set response headers.json(data)/text(string)/send(body)β return nativeResponseobjects.ok(),created(),noContent()β handy sugar for common status codes.lastβ inspect the last generatedResponseobject (router uses this fallback).
Response builders
WayResponse always returns native Fetch Response objects, so you can pass them directly to Bun APIs or other tooling without serialization tricks.
Returning native Responses β
Prefer the Fetch API? Return a Response directly and bunwayβs router will still merge middleware headers:
app.get("/raw", () => new Response("raw"));Next steps β
With the primitives in mind, learn how routing works in bunway by reading the Router guide, then explore the built-in Middleware.