Todo API 项目
这个项目把前面内容串起来:模块化路由、Zod 验证、统一错误、请求 ID 和基本 CRUD。
安装依赖
pnpm add hono zod @hono/zod-validator
pnpm add -D tsx typescript
Node.js 运行还需要:
pnpm add @hono/node-server
项目结构
src/
├─ index.ts
├─ app.ts
├─ routes/
│ └─ todos.ts
└─ middleware/
└─ request-id.ts
请求 ID 中间件
// src/middleware/request-id.ts
import type { MiddlewareHandler } from 'hono'
export const requestId: MiddlewareHandler = async (c, next) => {
const id = c.req.header('X-Request-Id') ?? crypto.randomUUID()
c.header('X-Request-Id', id)
await next()
}
Todo 路由
// src/routes/todos.ts
import { Hono } from 'hono'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
type Todo = {
id: string
title: string
done: boolean
}
const todos = new Map<string, Todo>()
const createTodoSchema = z.object({
title: z.string().min(1).max(100),
})
const updateTodoSchema = z.object({
title: z.string().min(1).max(100).optional(),
done: z.boolean().optional(),
})
export const todoRoutes = new Hono()
.get('/', (c) => {
return c.json({ data: Array.from(todos.values()) })
})
.post('/', zValidator('json', createTodoSchema), (c) => {
const input = c.req.valid('json')
const todo: Todo = {
id: crypto.randomUUID(),
title: input.title,
done: false,
}
todos.set(todo.id, todo)
return c.json({ data: todo }, 201)
})
.patch('/:id', zValidator('json', updateTodoSchema), (c) => {
const id = c.req.param('id')
const todo = todos.get(id)
if (!todo) {
return c.json({ message: 'Todo not found' }, 404)
}
const input = c.req.valid('json')
const nextTodo = { ...todo, ...input }
todos.set(id, nextTodo)
return c.json({ data: nextTodo })
})
.delete('/:id', (c) => {
const id = c.req.param('id')
if (!todos.delete(id)) {
return c.json({ message: 'Todo not found' }, 404)
}
return c.body(null, 204)
})
组合应用
// src/app.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { requestId } from './middleware/request-id'
import { todoRoutes } from './routes/todos'
export const app = new Hono()
app.use(logger())
app.use(requestId)
app.get('/health', (c) => c.json({ ok: true }))
app.route('/todos', todoRoutes)
app.notFound((c) => c.json({ message: 'Not Found' }, 404))
app.onError((err, c) => {
console.error(err)
return c.json({ message: 'Internal Server Error' }, 500)
})
Node.js 入口
// src/index.ts
import { serve } from '@hono/node-server'
import { app } from './app'
serve({
fetch: app.fetch,
port: Number(process.env.PORT ?? '3000'),
})
测试
curl http://localhost:3000/health
curl -X POST http://localhost:3000/todos \
-H "Content-Type: application/json" \
-d '{"title":"学习 Hono"}'
这个项目还没有数据库和鉴权,但结构已经能支撑继续扩展。下一步可以把 Map 换成数据库,并为 Todo 增加用户归属。
相关内容
- Hono 是什么 介绍 Hono 的定位、核心特点、Web Standards 思路、多运行时能力,以及它与传统 Node.js Web 框架的差异。
- 安装和 Hello World 学习使用 create-hono 创建 Hono 项目,分别了解通用模板和 Node.js 模板的 Hello World 写法。
- 运行时选择 对比 Hono 在 Node.js、Cloudflare Workers、Bun、Deno 等运行时中的入口写法、部署方式和适用场景。
- 路由基础 学习 Hono 的 GET、POST、动态参数、通配符、路由分组和模块化路由写法。
- Context 详解 介绍 Hono Context 的 req、json、text、html、redirect、header、status、set、get 等常用 API。
- 中间件机制 学习 Hono 中间件的执行顺序、自定义中间件写法、路径匹配、next 调用和常见使用场景。