RESTful 接口规划与路由拆分:前后端分离后接口越来越乱怎么办?
RESTful 接口规划是前后端协作的基础设施。本文围绕资源化设计讲解 RESTful 接口规范,用 HTTP 动词表达操作、用 URL 表达资源位置,并按资源边界拆分路由文件,帮你根治接口命名混乱、动词乱入、嵌套过深等问题,越写越顺。
问题背景
前端后端一旦分离开,接口就成了两边的"合同"。可往往写着写着接口就失控了:同一个资源有 /getUser 、 /userInfo 、 /user/get 三套叫法,POST 里传 id 做删除,查询参数和路径参数混着用。等到前端对接、后端维护,全凭猜。说实话,乱的根源往往是开始就没做接口规划。
原理说明
RESTful 的核心认知是: 把系统里的东西抽象成"资源"(Resource) ,用 HTTP 动词表达操作,用 URL 表达资源位置。一个资源一套 URL,做法统一、语义清晰。
- GET
/users:查列表 - GET
/users/:id:查单个 - POST
/users:新增 - PUT
/users/:id:整体更新 - PATCH
/users/:id:部分更新 - DELETE
/users/:id:删除
路径用复数名词,动词交给 HTTP method,永远不要用 getUserById 这种动词型的 URL。嵌套关系用层级表达,比如 GET /users/:id/orders 查某个用户的订单。
路由拆分则是对应着资源的边界,一个资源一个路由文件,既不臃肿,也好找好改。
示例代码
用 Express 拆资源路由,一个资源一个文件:
// routes/user.js
const express = require('express');
const router = express.Router();
const userService = require('../services/userService');
// 查列表
router.get('/', async (req, res, next) => {
try {
const list = await userService.list();
res.json({ code: 0, data: list });
} catch (err) { next(err); }
});
// 查单个
router.get('/:id', async (req, res, next) => {
try {
const user = await userService.getById(req.params.id);
res.json({ code: 0, data: user });
} catch (err) { next(err); }
});
// 新增
router.post('/', async (req, res, next) => {
try {
const created = await userService.create(req.body);
res.status(201).json({ code: 0, data: created });
} catch (err) { next(err); }
});
// 部分更新
router.patch('/:id', async (req, res, next) => {
try {
const updated = await userService.update(req.params.id, req.body);
res.json({ code: 0, data: updated });
} catch (err) { next(err); }
});
module.exports = router;
在 routes/index.js 汇总挂载:
const express = require('express');
const router = express.Router();
const userRouter = require('./user');
const orderRouter = require('./order');
router.use('/users', userRouter);
router.use('/orders', orderRouter);
module.exports = router;
常见坑与解决方案
- 坑一:同一个资源出现多个 URL 变体。解法:先画接口清单,把资源罗列全,再定 URL,杜绝即兴命名。
- 坑二:路径参数和查询参数混用,前端难缓存。解法:资源标识用路径参数,筛选分页用查询参数。
- 坑三:动词英文混在 URL 里。解法:删除
get/list/delete这类动词,交给 HTTP method 表达。 - 坑四:嵌套层级无限加深导致 URL 又长又难读。解法:超过两层就用查询参数或独立资源,别硬套层级。
小结
接口规划是前后端协作的基础设施,多花十分钟在清单上,后面能省下几天对接口的时间。路由按资源拆分,每个资源一个文件,配合清晰的动词与语义,越写越顺。下一件事,我们把公共逻辑收敛到中间件里去统一处理。
FAQ(常见问题)
Q:URL 里到底该用复数还是单数?
A:统一用复数名词表示资源集合,如 /users 、 /orders 。单个资源再通过 /users/:id 定位。关键是全团队保持一致,避免同一资源出现多套命名。
Q:为什么不能把 getUser 、 deleteUser 这类动词写进 URL?
A:动词本身的语义应由 HTTP 的 method(GET、POST、PUT、DELETE)表达,URL 只负责表达资源位置。动词进 URL 会造成同一动作多种叫法,语义混乱且难缓存。
Q:嵌套资源层次太深怎么办?
A: GET /users/:id/orders 这类一层嵌套可读性尚可,但超过两层就该改用查询参数(如 /orders?userId=1 )或独立资源,避免 URL 又长又难维护。