RESTful API 实际应用
把用户管理做成一套完整的 CRUD 接口:清单、创建、查询、更新、删除、错误。
Key Points一套 CRUD 就是五个端点:集合 GET/POST,单资源 GET/PUT/PATCH/DELETE,状态码与 Location 头把语义补全。
接口清单
| Method + path | Purpose | Success |
|---|---|---|
| GET /api/users | List with paging | 200 |
| POST /api/users | Create | 201 + Location |
| GET /api/users/{id} | Fetch one | 200 / 404 |
| PUT /api/users/{id} | Full replace | 200 / 204 |
| PATCH /api/users/{id} | Partial update | 200 / 204 |
| DELETE /api/users/{id} | Delete | 204 / 404 |
创建
Text
POST /api/users
Content-Type: application/json
{"name": "Alice", "email": "alice@example.com", "age": 30}
HTTP/1.1 201 Created
Location: /api/users/42
{"id": 42, "name": "Alice", "email": "alice@example.com", "age": 30,
"createdAt": "2026-10-31T03:12:00Z"}Return 201, not 200, and include Location. The client does not have to build the URL or re-query to learn the new id.
查询列表
Text
GET /api/users?status=active&sort=-createdAt&page=2&size=20
HTTP/1.1 200 OK
{
"items": [
{"id": 42, "name": "Alice", "status": "active"},
{"id": 41, "name": "Bob", "status": "active"}
],
"total": 137,
"page": 2,
"size": 20
}更新
Text
# 整体替换:没传的字段会被清空,所以要把完整对象发回来
PUT /api/users/42
{"name": "Alice Chen", "email": "alice@example.com", "age": 31}
HTTP/1.1 200 OK
{"id": 42, "name": "Alice Chen", "email": "alice@example.com", "age": 31}
# 局部更新:只发改动的字段
PATCH /api/users/42
{"age": 31}
HTTP/1.1 204 No Content删除
Text
DELETE /api/users/42
HTTP/1.1 204 No Content
# 再删一次
DELETE /api/users/42
HTTP/1.1 404 Not Found
{"error": {"code": "NOT_FOUND", "message": "user 42 does not exist"}}Deletion has two flavours: hard (row gone) and soft (a deletedAt flag filtered out of queries). Both look like DELETE to the client — choose internally and do not leak the difference.
错误响应
JSON
{"error": {"code": "EMAIL_TAKEN",
"message": "email already registered",
"details": [{"field": "email", "issue": "duplicate"}]}}code是稳定的机器可读串,前端用来分支message给人看,可以改文案details列出具体字段,表单可以直接高亮
接口清单
| 方法与路径 | 用途 | 成功 |
|---|---|---|
| GET /api/users | 分页列表 | 200 |
| POST /api/users | 创建 | 201 + Location |
| GET /api/users/{id} | 查单个 | 200 / 404 |
| PUT /api/users/{id} | 整体替换 | 200 / 204 |
| PATCH /api/users/{id} | 局部更新 | 200 / 204 |
| DELETE /api/users/{id} | 删除 | 204 / 404 |
创建
Text
POST /api/users
Content-Type: application/json
{"name": "Alice", "email": "alice@example.com", "age": 30}
HTTP/1.1 201 Created
Location: /api/users/42
{"id": 42, "name": "Alice", "email": "alice@example.com", "age": 30,
"createdAt": "2026-10-31T03:12:00Z"}返回 201 而不是 200,并带上 Location 指向新资源——客户端不需要自己拼 URL,也不会因为不知道 id 而再查一次。
查询列表
Text
GET /api/users?status=active&sort=-createdAt&page=2&size=20
HTTP/1.1 200 OK
{
"items": [
{"id": 42, "name": "Alice", "status": "active"},
{"id": 41, "name": "Bob", "status": "active"}
],
"total": 137,
"page": 2,
"size": 20
}更新
Text
# 整体替换:没传的字段会被清空,所以要把完整对象发回来
PUT /api/users/42
{"name": "Alice Chen", "email": "alice@example.com", "age": 31}
HTTP/1.1 200 OK
{"id": 42, "name": "Alice Chen", "email": "alice@example.com", "age": 31}
# 局部更新:只发改动的字段
PATCH /api/users/42
{"age": 31}
HTTP/1.1 204 No Content删除
Text
DELETE /api/users/42
HTTP/1.1 204 No Content
# 再删一次
DELETE /api/users/42
HTTP/1.1 404 Not Found
{"error": {"code": "NOT_FOUND", "message": "user 42 does not exist"}}删除有两种语义:硬删除(数据真的没了)和软删除(标记 deletedAt,查询默认过滤)。对外都是 DELETE,实现上按业务选,别让客户端感知差异。
错误响应
JSON
{"error": {"code": "EMAIL_TAKEN",
"message": "email already registered",
"details": [{"field": "email", "issue": "duplicate"}]}}code是稳定的机器可读串,前端用来分支message给人看,可以改文案details列出具体字段,表单可以直接高亮