Skip to Content
FrameworkExamples

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