API Routes
Create type-safe API endpoints with Bunbox
Creating an API Route
Create a route.ts file in the app/api/ directory:
// app/api/hello/route.ts
import { route } from "@ademattos/bunbox";
export const hello = route.get().handle(async (ctx) => {
return { message: "Hello, World!" };
});This creates a GET endpoint at /api/hello.
HTTP Methods
Use method builders for different HTTP methods:
// app/api/users/route.ts
import { route } from "@ademattos/bunbox";
export const listUsers = route.get().handle(async (ctx) => {
return { users: [] };
});
export const createUser = route.post().handle(async (ctx) => {
const user = ctx.body;
return { user, created: true };
});
export const deleteUser = route.delete().handle(async (ctx) => {
return { deleted: true };
});Available methods: .get(), .post(), .put(), .patch(), .delete()
Request Context
The handler receives a context object with useful properties:
export const getUser = route.get().handle(async (ctx) => {
// Access request properties
const { params, query, body, headers, url, method } = ctx;
// Return JSON response
return ctx.json({ message: "Hello" });
});Dynamic Routes
Use parameters in your API routes:
// app/api/users/[id]/route.ts
import { route } from "@ademattos/bunbox";
export const getUser = route.get().handle(async (ctx) => {
const userId = ctx.params.id;
return { userId, name: "John Doe" };
});Validation
Add validation with Zod schemas:
import { route } from "@ademattos/bunbox";
import { z } from "zod";
const UserSchema = z.object({
name: z.string(),
email: z.string().email(),
});
export const createUser = route
.post()
.body(UserSchema)
.handle(async (ctx) => {
// ctx.body is typed and validated
return { user: ctx.body };
});Middleware
Add middleware to routes:
import { route, defineMiddleware } from "@ademattos/bunbox";
const auth = defineMiddleware(async (ctx) => {
const token = ctx.headers.get("authorization");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
return { user: { id: "123" } };
});
export const getProfile = route
.get()
.use(auth)
.handle(async (ctx) => {
// ctx.user is available from middleware
return { user: ctx.user };
});Error Handling
Errors are automatically handled:
import { route, error } from "@ademattos/bunbox";
export const getUser = route.get().handle(async (ctx) => {
if (!ctx.query.id) {
return error("ID is required", 400);
}
return { id: ctx.query.id };
});Response Headers
Set custom response headers:
export const download = route.get().handle(async (ctx) => {
return new Response(JSON.stringify({ data: "hello" }), {
headers: {
"Content-Type": "application/json",
"X-Custom-Header": "value",
},
});
});OpenAPI Documentation
Add metadata for auto-generated API docs:
export const createUser = route
.post()
.meta({
summary: "Create a new user",
description: "Creates a user account",
tags: ["users"],
})
.body(UserSchema)
.handle(async (ctx) => {
return { user: ctx.body };
});See OpenAPI & Swagger for full documentation.
For streaming responses and Server-Sent Events, see the Streaming guide.