RESTful接口设计规范详解
1. 引言:什么是RESTful API?
RESTful API(Representational State Transfer)是一种基于HTTP协议的软件架构风格,它定义了一组约束和规范,用于创建可扩展、易于维护的Web服务。简单来说,它是一种让不同系统之间进行数据交互的标准方式。
为什么需要RESTful API?
-
统一标准:所有开发者使用相同的方式设计接口
-
易于理解:遵循HTTP协议的语义
-
前后端分离:前端和后端可以独立开发
-
可缓存性:提高性能
-
无状态:每个请求包含所有必要信息
2. 域名设计规范
2.1 专用API域名
推荐做法是将API部署在专用域名下:
https://api.example.com
优点:
-
专域专用,便于管理
-
可以单独做负载均衡
-
避免与主站cookie冲突
2.2 主域名下的API
对于小型项目或简单的API,可以放在主域名下:
https://www.example.org/api/
适用场景:
-
项目初期,API简单
-
不需要大规模扩展
-
节省域名成本
3. 版本控制(Versioning)
3.1 URL路径版本控制(推荐)
http://www.example.com/app/1.0/foo
http://www.example.com/app/1.1/foo
http://www.example.com/app/2.0/foo
优点:
-
直观明了
-
易于调试
-
浏览器可直接访问
3.2 HTTP头信息版本控制
Accept: vnd.example-com.foo+json; version=1.0
Accept: vnd.example-com.foo+json; version=1.1
GitHub采用此方式,但:
-
不够直观
-
需要额外解析头信息
-
浏览器直接访问困难
4. 端点(Endpoint)设计规范
4.1 资源命名原则
正确做法:
-
使用名词而非动词
-
使用复数形式
-
与数据库表名对应
错误示例:
/getProducts
/listorders
/retreiveClientByOrder?orderId=1
正确示例:
GET /products # 获取所有产品
POST /products # 创建新产品
GET /products/4 # 获取ID为4的产品
PUT /products/4 # 更新产品4
DELETE /products/4 # 删除产品4
4.2 资源层级关系
对于关联资源:
GET /zoos/ID/animals # 获取某动物园的所有动物
DELETE /zoos/ID/animals/ID # 删除某动物园的特定动物
5. HTTP方法详解
HTTP方法 | SQL对应 | 描述 | 幂等性 |
---|---|---|---|
GET | SELECT | 获取资源 | 是 |
POST | INSERT | 创建资源 | 否 |
PUT | UPDATE | 完整更新资源 | 是 |
PATCH | UPDATE | 部分更新资源 | 否 |
DELETE | DELETE | 删除资源 | 是 |
HEAD | - | 获取头信息 | 是 |
OPTIONS | - | 获取可用方法 | 是 |
示例场景:
GET /zoos # 列出所有动物园
POST /zoos # 新建动物园
GET /zoos/ID # 获取特定动物园
PUT /zoos/ID # 更新整个动物园信息
PATCH /zoos/ID # 部分更新动物园信息
DELETE /zoos/ID # 删除动物园
6. 过滤、分页与排序
6.1 常用过滤参数
?limit=10 # 返回10条记录
?offset=10 # 从第11条开始返回
?page=2&per_page=100 # 第2页,每页100条
?sortby=name&order=asc # 按名称升序
?animal_type_id=1 # 筛选特定类型
6.2 参数设计原则
允许合理的冗余,例如:
GET /zoos/ID/animals
GET /animals?zoo_id=ID
两种方式都可以表示"获取某动物园的动物"
7. 状态码规范
7.1 主要状态码分类
状态码 | 类别 | 描述 |
---|---|---|
1xx | 信息 | 请求已被接收,继续处理 |
2xx | 成功 | 请求已成功处理 |
3xx | 重定向 | 需要进一步操作 |
4xx | 客户端错误 | 请求包含错误 |
5xx | 服务器错误 | 服务器处理错误 |
7.2 常用状态码详解
成功类(2xx):
-
200 OK - GET请求成功
-
201 Created - POST/PUT成功创建资源
-
204 No Content - DELETE成功,无返回内容
重定向类(3xx):
-
301 永久重定向
-
302 临时重定向
-
304 未修改(缓存)
客户端错误(4xx):
-
400 Bad Request - 请求参数错误
-
401 Unauthorized - 需要认证
-
403 Forbidden - 无权限
-
404 Not Found - 资源不存在
服务器错误(5xx):
-
500 Internal Server Error - 服务器内部错误
-
503 Service Unavailable - 服务不可用
8. 错误处理规范
8.1 错误响应格式
{"error": {"code": "INVALID_PARAM","message": "用户名不能为空","detail": {"field": "username","requirement": "必须包含3-20个字符"}}
}
8.2 最佳实践
-
4xx错误必须包含清晰的错误信息
-
错误码使用大写蛇形命名(如INVALID_PARAM)
-
提供错误文档链接(如GitHub API)
9. 返回结果设计
9.1 基本规范
操作 | 返回结果 |
---|---|
GET /collections | 资源数组 |
GET /collections/ID | 单个资源对象 |
POST /collections | 新建的资源对象 |
PUT /collections/ID | 更新后的资源对象 |
DELETE /collections/ID | 空内容 |
9.2 示例
获取产品列表:
[{"id": 1,"name": "iPhone","price": 5999},{"id": 2,"name": "MacBook","price": 9999}
]
获取单个产品:
{"id": 1,"name": "iPhone","price": 5999,"created_at": "2023-01-01T00:00:00Z"
}
10. 超媒体API(HATEOAS)
10.1 什么是超媒体API?
在返回结果中包含相关操作的链接,客户端无需事先知道API结构。
10.2 GitHub API示例
{"current_user_url": "https://api.github.com/user","repository_url": "https://api.github.com/repos/{owner}/{repo}","issues_url": "https://api.github.com/issues"
}
10.3 实现示例
{"id": 1,"name": "iPhone","price": 5999,"_links": {"self": {"href": "https://api.example.com/products/1"},"collection": {"href": "https://api.example.com/products"}}
}
11. 数据格式选择
11.1 JSON vs XML
JSON优势:
-
更轻量
-
更易解析
-
前端友好
-
成为事实标准
XML示例:
<?xml version="1.0" encoding="utf-8"?>
<book><name>红楼梦</name><price>9999</price><author>曹雪芹</author><pub_data>2020-9-8</pub_data>
</book>
JSON示例:
{"name": "三国演义","price": 1,"author": "罗贯中","pub_data": "2000-1-1"
}
12. 完整URL结构示例
http://www.xx.com:80/students?username=xiaoming&pwd=123
-
协议:http
-
域名:www.xx.com
-
端口:80
-
路径:/students
-
查询字符串:username=xiaoming&pwd=123
13. 最佳实践总结
-
保持一致性:整个API使用相同的命名和结构
-
安全性:始终使用HTTPS
-
版本控制:从v1开始,URL中包含版本号
-
过滤分页:大数据集必须支持
-
正确状态码:准确反映操作结果
-
错误处理:提供清晰的错误信息
-
文档:维护完整的API文档
14. 常见问题解答
Q:为什么用复数名词?
A:表示资源集合,更符合REST理念。如/products代表所有产品的集合。
Q:PUT和PATCH的区别?
A:PUT需要发送完整资源,PATCH只需发送要修改的字段。
Q:如何设计复杂的查询?
A:可以使用特殊查询参数,如:
/search?q=keyword&sort=price&order=desc
Q:什么时候用401 vs 403?
A:401表示未认证(需要登录),403表示已认证但无权限。
15. 结语
设计良好的RESTful API就像设计一个清晰易懂的语言,让不同的系统能够流畅沟通。遵循这些规范,你的API将更易于使用、维护和扩展。记住,好的API设计始终以开发者体验为中心。