Sakila 管理后台 API 综合练习
本练习面向具有前端经验、刚开始学习 Node.js 后端的开发者。你将基于 MySQL 官方 sakila 示例数据库,逐步完成一套只有管理员登录后才能操作的 Express 5 API。
本目录提供接口契约、TypeScript 类型、代码骨架、提示、易错点和验收方法,但不会直接给出核心 Sequelize 查询、事务、锁和 Raw SQL 的完整答案。
最终请求链路
前端或 curl
↓ Authorization: Bearer <JWT>
Express Router
↓
express-validator
↓
authenticateAdmin
↓
Controller
↓
Service
↓
Sequelize Model / Raw SQL
↓
MySQL sakila_training
PM2 负责管理 Node.js 进程,Nginx 负责接收公网请求和反向代理;它们不代替应用完成身份认证。
业务边界
staff是 Sakila 门店员工,参与租赁和收款。admin_user是本练习新增的后台登录身份。- 第一阶段所有启用的
admin_user都是全局管理员,不设计复杂 RBAC。 - 除登录和健康检查外,所有 Sakila API 都必须通过
authenticateAdmin。 - 建议复制数据库为
sakila_training,不要破坏唯一的原始 Sakila 数据。 - Express 能处理的响应遵循当前项目约定:HTTP 状态为 200,业务结果由 JSON
code表示。
学习路线
- 00 项目目标、环境和统一规则
- 01 管理员账号表设计
- 02 项目结构与共享 TypeScript 类型
- 03 Sequelize Models 与 Associations
- 04 创建第一个管理员
- 05 管理员登录与 JWT
- 06 JWT 鉴权中间件
- 07 管理员账号管理
- 08 Actor CRUD
- 09 Customer 管理
- 10 Film 查询 API
- 11 Rental 租赁流程
- 12 Payment 与事务
- 13 Raw Query 经营报表
- 14 校验、错误、日志与审计
- 15 安全、性能与并发
- 16 最终综合项目
推荐完成顺序
00~04:建立数据库与管理员模型
↓
05~07:完成登录、JWT 和账号管理
↓
08:用 Actor 跑通第一套受保护 CRUD
↓
09~10:练习 Association、DTO、分页和 N+1
↓
11~12:练习事务、锁、状态流转和金额
↓
13:练习 ORM 边界与 Raw SQL
↓
14~15:补齐日志、安全、性能与并发
↓
16:独立整合并验收
不要一次创建全部代码。完成前一章的验收后,再进入下一章。
统一响应类型
成功:
{
"code": "OK",
"message": "success",
"data": {}
}
失败:
{
"code": "INVALID_CREDENTIALS",
"message": "用户名或密码错误",
"data": null
}
分页:
{
"code": "OK",
"message": "success",
"data": {
"list": [],
"total": 0,
"page": 1,
"pageSize": 20,
"totalPages": 0
}
}
由于业务错误仍返回 HTTP 200:
- 前端必须检查
code; - Pino 日志必须记录
businessCode; - Nginx 和 HTTP 监控不能仅根据 HTTP status 判断业务成败;
curl --fail-with-body无法识别业务错误。
这个约定只覆盖“请求已经到达 Express,并被应用正常转换为 JSON”的业务错误。Nginx 的 502/504、TLS 或网络失败、进程崩溃,以及响应头发出后的 Stream 错误,不保证得到 HTTP 200 或上述 JSON 结构。
公开与受保护接口
公开接口:
GET /health
POST /api/auth/login
需要管理员身份:
GET /api/auth/me
PATCH /api/auth/password
POST /api/auth/logout-all
GET /api/admin/users
POST /api/admin/users
PATCH /api/admin/users/:adminId/status
GET /api/sakila/actors
POST /api/sakila/actors
GET /api/sakila/customers
GET /api/sakila/films
POST /api/sakila/rentals
PATCH /api/sakila/rentals/:rentalId/return
GET /api/sakila/reports/daily-revenue
完整接口以各章节为准。
每道练习如何使用
每道练习会区分:
已提供
[✓] HTTP 路径和方法
[✓] Request、Response 和 DTO 类型
[✓] Router、Controller、Service 函数签名
[✓] Sequelize Model 或 Raw Query 骨架
[✓] 业务错误码和验收目标
需要完成
[ ] express-validator 规则
[ ] Sequelize 字段和查询选项
[ ] 业务状态判断
[ ] Model 到 DTO 的转换
[ ] JWT 签发与验证
[ ] 事务、锁和并发处理
[ ] Raw SQL 主体
[ ] curl 验收和问题复盘
进阶挑战
[ ] 集成测试
[ ] EXPLAIN
[ ] 请求日志和审计
[ ] 并发故障注入
[ ] 监控与安全加固
通用完成标准
[ ] 不使用无必要的 any
[ ] 不把 req.body 整体传给 Model.update()
[ ] 不在日志、JWT、DTO 中暴露密码或 password_hash
[ ] 所有列表都有 pageSize 上限和稳定排序
[ ] 所有 Raw SQL 都参数化处理用户输入
[ ] 日期区间使用左闭右开
[ ] DECIMAL 不直接假设为 JavaScript number
[ ] 未知错误不把 SQL 和服务器路径返回客户端
[ ] 所有 Sakila 业务 Router 都经过 authenticateAdmin
[ ] 能使用 curl 复现成功、校验失败和未登录场景
依赖说明
当前项目已经具备主要依赖:
express
express-validator
sequelize
mysql2
jsonwebtoken
argon2
pino / pino-http
练习不会要求通过 sequelize.sync({ force: true }) 修改 Sakila。新增表应使用明确 DDL 或迁移思路创建,并在执行前确认目标数据库是练习库。
建议复盘方式
每完成一个接口,记录:
请求示例
响应示例
实际执行的 SQL
遇到的 Sequelize/TypeScript 问题
错误版本为什么错误
最终如何验证
一次只解决一个接口,比复制一整套答案更能建立后端能力。