使用 Koa 构建你的第一个 API
如果你熟悉 JavaScript 并想构建后端 API,Koa 值得认真考虑。它简洁、现代,并且从底层开始就围绕 async/await 构建——这意味着更清晰的代码,不再有回调地狱。本 Koa API 教程将带你了解基础知识:设置项目、理解中间件的工作原理,以及构建一个带有 GET 和 POST 端点的小型 REST API。
核心要点
- Koa 是一个轻量级的 Node.js 框架,没有捆绑中间件——你只需组合所需的功能。
- 它的”洋葱模型”中间件级联让每个函数在下游处理程序之前和之后都能运行逻辑。
ctx对象统一了请求和响应数据,使路由处理程序保持清晰和可读。- 使用
@koa/router和@koa/bodyparser,你可以在单个文件中搭建一个可工作的 REST API。
前置要求
- Node.js 20+(推荐使用当前 LTS 版本)
- JavaScript 基础知识,包括
async/await - 终端和文本编辑器
什么是 Koa,为什么使用它?
Koa 是由 Express 背后的团队创建的轻量级 Node.js Web 框架。与 Express 不同,Koa 没有捆绑中间件——你只添加所需的功能。它的突出特性是中间件级联,有时称为”洋葱模型”,其中每个中间件函数在链中的下一个函数之前和之后都会运行代码。
这使得 Koa 的 API 基础概念易于理解:每个请求通过你的中间件堆栈向内流动,响应则向外流回。
步骤 1 — 设置你的项目
创建一个新目录并初始化它:
mkdir koa-items-api && cd koa-items-api
npm init -y
在 package.json 中添加 "type": "module" 以使用 ES 模块语法,然后安装依赖:
npm install koa @koa/router @koa/bodyparser
- koa — 核心框架
- @koa/router — 官方路由中间件
- @koa/bodyparser — 解析传入的 JSON 请求体
步骤 2 — 理解 Koa 中间件 API
每个 Koa 中间件都是一个 async 函数,接收一个 ctx(上下文)对象和一个 next 函数。ctx 对象将请求和响应合并到一个地方——ctx.method、ctx.path、ctx.request.body 和 ctx.body(响应)都在那里。
调用 await next() 将控制权传递给下一个中间件。这是一个简单的日志记录示例:
app.use(async (ctx, next) => {
const start = Date.now()
await next()
console.log(`${ctx.method} ${ctx.path} — ${Date.now() - start}ms`)
})
注意,await next() 之后的代码在下游中间件完成后运行。这就是洋葱模型的实际应用。
Discover how at OpenReplay.com.
步骤 3 — 使用 Koa 构建 REST API
创建 app.js,实现一个小型的内存项目 API:
import Koa from "koa"
import Router from "@koa/router"
import bodyParser from "@koa/bodyparser"
const app = new Koa()
const router = new Router()
// 内存数据存储
let nextId = 3
let items = [
{ id: 1, name: "Keyboard" },
{ id: 2, name: "Monitor" },
]
// GET /items — 返回所有项目
router.get("/items", (ctx) => {
ctx.body = { success: true, data: items }
})
// GET /items/:id — 返回单个项目
router.get("/items/:id", (ctx) => {
const item = items.find((i) => i.id === Number(ctx.params.id))
if (!item) {
ctx.status = 404
ctx.body = { error: "Item not found" }
return
}
ctx.body = { success: true, data: item }
})
// POST /items — 创建新项目
router.post("/items", (ctx) => {
const { name } = ctx.request.body
if (!name) {
ctx.status = 400
ctx.body = { error: "Name is required" }
return
}
const newItem = { id: nextId++, name }
items.push(newItem)
ctx.status = 201
ctx.body = { success: true, data: newItem }
})
app.use(bodyParser())
app.use(router.routes())
app.use(router.allowedMethods())
app.listen(3000, () => console.log("Server running on http://localhost:3000"))
注意: 原始的
id: items.length + 1方法在删除项目时会出现问题,因为数组长度会缩小而现有 ID 不会。单独的nextId计数器可以避免重复 ID。
启动服务器:
node app.js
测试你的端点
获取所有项目:
curl http://localhost:3000/items
创建一个项目:
curl -X POST http://localhost:3000/items \
-H "Content-Type: application/json" \
-d '{"name": "Mouse"}'
预期响应:
{ "success": true, "data": { "id": 3, "name": "Mouse" } }
请求不存在的项目:
curl http://localhost:3000/items/99
{ "error": "Item not found" }
router.allowedMethods() 会自动处理不支持的 HTTP 方法,返回正确的 405 Method Not Allowed 响应,无需任何额外代码。
总结
Koa 的优势在于其简洁性。ctx 对象将请求和响应处理集中在一个地方,中间件级联让你精确控制请求如何流经你的应用程序。这个基础——一个 Koa 服务器、用于路由的 @koa/router 和用于 JSON 解析的 @koa/bodyparser——就是你开始使用 Koa 构建 REST API 所需的全部。从这里开始,你可以逐层添加真实数据库、验证或错误处理中间件。
常见问题
Koa 不附带任何内置中间件,因此你只需安装项目所需的功能。它还原生使用 async/await 而不是回调,这简化了错误处理和控制流。Express 依赖传统的基于回调的中间件签名,而 Koa 的洋葱模型让每个中间件在下游处理程序之前和之后都能运行逻辑。
是的。Koa 稳定、维护良好,并被许多团队用于生产环境。由于它在设计上是最小化的,你可以选择自己的路由器、请求体解析器和错误处理层。这让你完全控制依赖堆栈并保持框架占用空间小,这可以简化审计和长期维护。
在中间件堆栈的顶部放置一个 try/catch 中间件。因为 Koa 使用 async/await,下游抛出的任何错误都会冒泡到外部处理程序。然后你可以设置 ctx.status 和 ctx.body 来返回一致的错误响应。这个单一中间件取代了在每个路由中重复错误检查的需要。
可以。Koa 及其官方包(如 @koa/router 和 @koa/bodyparser)包含 TypeScript 类型定义。你可以使用 ts-node 或构建步骤设置标准 TypeScript 项目,像往常一样导入 Koa,并在 ctx 对象、路由参数和请求体上获得完整的类型安全。
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.