Examples
CRUD: Orders
Representative handlers — list with query and create. The remaining methods ([id:uuid]/get, put, patch, delete) follow the same shape: { id } = c.req.valid("param") (auto-injected from filepath), call one repository function, set a success status before return, throw HTTPException for errors, let the framework serialize.
app/orders/get.ts — List (with pagination query)
// app/orders/repository.ts — every DB call + business rule lives here (handlers never call db.*)
import { HTTPException } from "hono/http-exception";
import { db, eq, desc, count } from "app/db";
import { orders } from "./orders.table";
export async function listOrders(q: { page: number; pageSize: number }) {
const [data, [{ total }]] = await Promise.all([
db.select().from(orders).orderBy(desc(orders.createdAt)).limit(q.pageSize).offset((q.page - 1) * q.pageSize),
db.select({ total: count() }).from(orders),
]);
return { data, total };
}
export async function getOrder(id: string) {
const [row] = await db.select().from(orders).where(eq(orders.id, id));
if (!row) throw new HTTPException(404, { message: "Order not found", cause: { code: "NOT_FOUND" } });
return row;
}
export async function createOrder(input: { customerName: string; total: number }) {
const [row] = await db.insert(orders)
.values({ id: crypto.randomUUID(), ...input, status: "pending", createdAt: Date.now() })
.returning();
return row;
}// app/orders/get.ts
import { z } from "@hono/zod-openapi";
import { listOrders } from "./repository";
export const schema = {
query: z.object({
page: z.coerce.number().int().min(1).default(1),
pageSize: z.coerce.number().int().min(1).max(100).default(20),
}),
};
export default async function handler(c) {
return listOrders(c.req.valid("query")); // { data, total }
}app/orders/post.ts — Create
// app/orders/post.ts
import { z } from "@hono/zod-openapi";
import { createOrder } from "./repository";
export const schema = {
body: z.object({
customerName: z.string().min(1),
total: z.number().positive(),
}),
};
export default async function handler(c) {
c.status(201);
return createOrder(c.req.valid("json"));
}app/orders/[id:uuid]/get.ts — Get by ID (typed param)
// app/orders/[id:uuid]/get.ts — thin: validate, call the repository
import { getOrder } from "../repository"; // throws HTTPException(404) → { error, message, code }
export const schema = {}; // empty — id is auto-injected from [id:uuid]
export default async function handler(c) {
const { id } = c.req.valid("param");
return getOrder(id);
}Last updated on