RESTful API 不仅是一套规则,更是一种哲学和设计风格
1. 什么是 RESTful API?
首先,我们需要理解两个核心概念:
- REST : 表述性状态转移 ,由 Roy Fielding 博士在其博士论文中提出。它是一种软件架构风格,而不是标准。它是一组设计原则和约束条件,基于 HTTP 协议。
- RESTful API: 符合 REST 架构风格设计的 API。我们可以理解为 "REST 式的 API"。
简单来说,RESTful API 将网络上的所有事物(数据、服务)都抽象为资源。我们通过统一的接口(HTTP 方法)对资源进行操作,从而实现客户端与服务器的交互。
2. REST 的核心架构约束(六大原则)
要真正理解 RESTful,必须了解其背后的六个约束。满足这些约束的 API 才能称为 "RESTful"。
- 客户端-服务器: 关注点分离。客户端负责用户界面和用户体验,服务器负责数据存储、业务逻辑和安全。两者可以独立演化。
- 无状态 : 这是最关键的原则之一。 每个来自客户端的请求必须包含服务器处理该请求所需的所有信息。服务器不应存储任何客户端上下文。会话状态完全由客户端负责(例如,通过 Token)。
- 好处: 可伸缩性高,服务器无需维护状态,可以轻松部署到集群。
- 坏处: 每次请求可能需要携带更多重复数据(如认证 Token)。
 
- 可缓存: 响应必须明确标示自己是否可缓存,以防止客户端获取过期或不恰当的数据。这可以大大提高性能。
- 统一接口 : 这是 REST 系统设计的核心。它简化了架构,解耦了各个部分。具体包括:
- 资源的标识(URI)
- 通过表述对资源执行操作(JSON, XML)
- 自描述消息
- 超媒体作为应用状态引擎(HATEOAS)
 
- 分层系统: 系统可以由多个层次组成,每个层次只知道相邻的层次。这提高了系统的可扩展性和安全性。例如,你可以在客户端和服务器之间加入负载均衡器、网关、防火墙等,而客户端无需知道这些细节。
- 按需代码(可选): 服务器可以临时向客户端传输逻辑代码(如 JavaScript),供客户端执行。这是唯一一个可选的约束。
3. RESTful API 设计最佳实践(具体怎么做)
现在,我们抛开理论,看看在实际开发中如何设计一个优秀的 RESTful API。
3.1. 面向资源设计 URI
URI 的核心是标识资源,而不是动作。
- 
使用名词,而非动词: - 不推荐 : /getUsers,/createOrder,/deleteProduct/123
- 推荐 : GET /users,POST /orders,DELETE /products/123
 
- 不推荐 : 
- 
资源使用复数名词: - GET /users(获取所有用户)
- GET /users/123(获取 ID 为 123 的用户)
 
- 
使用嵌套结构表达关联关系: - GET /users/123/orders(获取用户 123 的所有订单)
- GET /users/123/orders/456(获取用户 123 的 ID 为 456 的订单)
 
- 
使用连字符 -提高可读性,避免下划线_:- GET /published-articles(而非- /published_articles)
 
- 
使用小写字母: - GET /users(而非- /Users)
 
3.2. 正确使用 HTTP 方法(动词)
HTTP 方法定义了要对资源执行的操作,这是 "统一接口" 的关键。
| HTTP 方法 | 描述 | 对应 SQL | 幂等性 | 安全性 | 
|---|---|---|---|---|
| GET | 获取资源(一个或多个) | SELECT | 是 | 是 | 
| POST | 创建新资源 | INSERT | 否 | 否 | 
| PUT | 完整更新资源(客户端提供完整资源) | UPDATE | 是 | 否 | 
| PATCH | 部分更新资源(客户端提供要修改的字段) | UPDATE | 否 | 否 | 
| DELETE | 删除资源 | DELETE | 是 | 否 | 
重要概念解释:
- 幂等性 : 无论执行多少次,效果都一样。GET,PUT,DELETE是幂等的。例如,多次DELETE /users/123,结果都是用户 123 被删除。
- 安全性 : 不改变服务器状态。只有 GET是安全的。
示例:
- GET /users-> 200 OK (用户列表)
- POST /users(Body: 用户信息) -> 201 Created (创建成功)
- GET /users/123-> 200 OK (用户 123 的详情)
- PUT /users/123(Body: 完整的用户信息) -> 200 OK (更新成功)
- PATCH /users/123(Body:- {"name": "新名字"}) -> 200 OK (部分更新成功)
- DELETE /users/123-> 204 No Content (删除成功,无返回体)
3.3. 合理利用 HTTP 状态码
状态码用于告知客户端请求的结果。不要在所有响应中都返回 200 OK,然后在 Body 里说明错误。
- 
2xx 成功: - 200 OK- 通用成功状态。
- 201 Created- 资源创建成功。响应头- Location应包含新资源的 URI。
- 204 No Content- 请求成功,但无内容返回(如- DELETE成功)。
 
- 
4xx 客户端错误: - 400 Bad Request- 通用客户端错误,服务器无法理解请求(如参数错误)。
- 401 Unauthorized- 未认证,需要身份验证。
- 403 Forbidden- 服务器理解请求,但拒绝授权(认证成功但权限不足)。
- 404 Not Found- 资源不存在。
- 405 Method Not Allowed- 不允许的 HTTP 方法。
- 409 Conflict- 请求与当前服务器状态冲突(如修改旧版本数据)。
 
- 
5xx 服务器错误: - 500 Internal Server Error- 通用服务器错误。
 
3.4. 返回统一的 JSON 响应体
即使出错,也应返回结构化的 JSON 数据。
成功响应:
            
            
              json
              
              
            
          
          {
  "code": 200,
  "message": "success",
  "data": {
    "id": 123,
    "name": "张三",
    "email": "zhangsan@example.com"
  }
  // 可以加入分页信息等
  // "pagination": { ... }
}错误响应:
            
            
              json
              
              
            
          
          {
  "code": 404,
  "message": "用户不存在",
  "timestamp": "2023-10-25T10:30:00Z",
  "path": "/api/v1/users/999",
  "details": "更多错误细节..."
}3.5. 提供 API 版本管理
API 会演化,必须进行版本控制,避免破坏现有客户端。
- 
URI Path 方式(最常用): - GET /api/v1/users
- GET /api/v2/users
 
- 
Query Parameter 方式: - GET /api/users?version=1
 
- 
HTTP Header 方式: - GET /api/users
- Headers: Accept: application/vnd.myapi.v1+json
 
推荐使用 URI Path 方式,因为它最直观、最简单。
3.6. 数据过滤、排序、搜索和分页
对于集合资源,这些功能是必不可少的。
- 过滤 : GET /users?role=admin&status=active
- 搜索 : GET /users?name=张(模糊搜索名字中含 "张" 的用户)
- 排序 : GET /users?sort=-created_at,username(-表示降序)
- 分页 : GET /users?page=2&limit=20或GET /users?offset=20&limit=20
3.7. 安全性
- 始终使用 HTTPS。
- 身份认证 : 使用标准方案,如 JWT (JSON Web Tokens)、OAuth 2.0。Token 通常通过 Authorization请求头传递:Authorization: Bearer <token>。
- 授权: 确保用户只能访问其权限范围内的资源。
- 限流 : 防止 API 被滥用,应返回 429 Too Many Requests。
3.8. 超媒体 API (HATEOAS)
这是 REST 最高级的约束,但实践中并不总是被实现。它使 API 变得"可发现"。
在响应中提供相关资源的链接:
            
            
              json
              
              
            
          
          {
  "id": 123,
  "name": "张三",
  "links": [
    {
      "rel": "self",
      "href": "/api/v1/users/123",
      "method": "GET"
    },
    {
      "rel": "orders",
      "href": "/api/v1/users/123/orders",
      "method": "GET"
    },
    {
      "rel": "update",
      "href": "/api/v1/users/123",
      "method": "PUT"
    }
  ]
}客户端可以通过解析这些 links 来导航整个应用,而无需硬编码 URI 结构。
总结:一个好的 RESTful API 是什么样的?
一个优秀的、符合规范的 RESTful API 应该具备以下特点:
- 直观的: URI 清晰明了,使用名词标识资源。
- 语义化的: 正确使用 HTTP 方法和状态码。
- 一致的: 响应格式、错误处理、命名规则在整个 API 中保持一致。
- 无状态的: 不依赖服务器端的会话。
- 健壮的: 能妥善处理各种异常和错误。
- 安全的: 使用 HTTPS、适当的认证和授权机制。
- 可维护和可扩展的: 通过版本控制来管理迭代。