REST API 设计原则

REST(Representational State Transfer)是一种架构风格,用于设计网络应用程序的 API。RESTful API 是基于 REST 原则设计的 Web API。


什么是 REST

REST(Representational State Transfer,表述性状态转移)是一种软件架构风格,用于设计网络应用程序的 API。

REST 的核心概念

  • 资源(Resource):网络上的任何信息都可以是资源,如用户、文章、订单等
  • URI(Uniform Resource Identifier):资源的唯一标识符
  • HTTP 方法:GET、POST、PUT、DELETE 等
  • 表述(Representation):资源的表现形式,通常是 JSON 或 XML

RESTful API 设计原则

1. 使用名词,不使用动词

❌ 错误示例

GET /getUsers
POST /createUser
PUT /updateUser
DELETE /deleteUser

✅ 正确示例

GET /users
POST /users
PUT /users/{id}
DELETE /users/{id}

2. 使用复数名词

❌ 错误示例

GET /user
POST /user

✅ 正确示例

GET /users
POST /users

3. 使用 HTTP 方法表示操作

HTTP 方法用途示例
GET获取资源GET /users - 获取所有用户
POST创建资源POST /users - 创建新用户
PUT完整更新资源PUT /users/{id} - 更新整个用户信息
PATCH部分更新资源PATCH /users/{id} - 更新用户的部分信息
DELETE删除资源DELETE /users/{id} - 删除用户

4. 使用正确的 HTTP 状态码

状态码含义使用场景
200 OK成功GET、PUT、PATCH 成功
201 Created已创建POST 成功创建资源
204 No Content无内容DELETE 成功
400 Bad Request请求错误请求参数错误
401 Unauthorized未授权未提供认证信息
403 Forbidden禁止访问无权限访问资源
404 Not Found未找到资源不存在
409 Conflict冲突资源冲突(如重复创建)
500 Internal Server Error服务器错误服务器内部错误

5. 使用嵌套资源表示关系

示例

GET /users/{userId}/posts          # 获取用户的所有文章
GET /users/{userId}/posts/{postId} # 获取用户的特定文章
POST /users/{userId}/posts         # 为用户创建文章

6. 使用查询参数进行过滤、排序和分页

示例

GET /users?page=1&limit=10              # 分页
GET /users?status=active                # 过滤
GET /users?sort=created_at&order=desc   # 排序
GET /users?search=张三                   # 搜索

7. 使用版本控制

方式1:URL 路径版本控制

GET /v1/users
GET /v2/users

方式2:HTTP 头版本控制

GET /users
Accept: application/vnd.api+json;version=1

8. 使用统一的响应格式

成功响应示例

{
  "code": 200,
  "message": "success",
  "data": {
    "id": 1,
    "name": "张三",
    "email": "zhangsan@example.com"
  }
}

错误响应示例

{
  "code": 404,
  "message": "用户不存在",
  "error": "User not found"
}

RESTful API 设计示例

用户管理 API

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    // GET /api/v1/users - 获取所有用户
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers(
            @RequestParam(required = false) Integer page,
            @RequestParam(required = false) Integer limit,
            @RequestParam(required = false) String status) {
        // 实现逻辑
        return ResponseEntity.ok(users);
    }
    
    // GET /api/v1/users/{id} - 获取指定用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        if (user == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(user);
    }
    
    // POST /api/v1/users - 创建用户
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
        User createdUser = userService.createUser(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }
    
    // PUT /api/v1/users/{id} - 完整更新用户
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody @Valid User user) {
        User updatedUser = userService.updateUser(id, user);
        if (updatedUser == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(updatedUser);
    }
    
    // PATCH /api/v1/users/{id} - 部分更新用户
    @PatchMapping("/{id}")
    public ResponseEntity<User> patchUser(@PathVariable Long id, @RequestBody Map<String, Object> updates) {
        User updatedUser = userService.patchUser(id, updates);
        if (updatedUser == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(updatedUser);
    }
    
    // DELETE /api/v1/users/{id} - 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        boolean deleted = userService.deleteUser(id);
        if (!deleted) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.noContent().build();
    }
}

常见错误与注意事项

1. 不要在 URI 中使用动词

❌ 错误

POST /users/create
GET /users/get/{id}

✅ 正确

POST /users
GET /users/{id}

2. 不要使用单数名词

❌ 错误

GET /user
POST /user

✅ 正确

GET /users
POST /users

3. 不要忽略 HTTP 状态码

❌ 错误:所有请求都返回 200,在响应体中表示错误

{
  "status": "error",
  "message": "用户不存在"
}

✅ 正确:使用正确的 HTTP 状态码

// HTTP 404 Not Found
{
  "code": 404,
  "message": "用户不存在"
}

4. 不要过度嵌套资源

❌ 错误

GET /users/{userId}/posts/{postId}/comments/{commentId}/replies/{replyId}

✅ 正确

GET /replies/{replyId}?commentId={commentId}

5. 不要忽略版本控制

对于长期维护的 API,应该从一开始就考虑版本控制。


实际应用场景

1. 电商系统 API

GET    /api/v1/products              # 获取商品列表
GET    /api/v1/products/{id}         # 获取商品详情
POST   /api/v1/products              # 创建商品
PUT    /api/v1/products/{id}         # 更新商品
DELETE /api/v1/products/{id}        # 删除商品

GET    /api/v1/orders                # 获取订单列表
GET    /api/v1/orders/{id}           # 获取订单详情
POST   /api/v1/orders                # 创建订单
PATCH  /api/v1/orders/{id}/status    # 更新订单状态

2. 博客系统 API

GET    /api/v1/posts                 # 获取文章列表
GET    /api/v1/posts/{id}            # 获取文章详情
POST   /api/v1/posts                 # 创建文章
PUT    /api/v1/posts/{id}            # 更新文章
DELETE /api/v1/posts/{id}           # 删除文章

GET    /api/v1/posts/{id}/comments   # 获取文章评论
POST   /api/v1/posts/{id}/comments   # 创建评论

总结

RESTful API 设计要点:

  • 使用名词和复数形式:资源使用名词,使用复数形式
  • 使用 HTTP 方法:GET、POST、PUT、PATCH、DELETE
  • 使用正确的状态码:200、201、204、400、404 等
  • 使用嵌套资源:表示资源之间的关系
  • 使用查询参数:进行过滤、排序和分页
  • 版本控制:从设计之初考虑版本管理
  • 统一响应格式:保持 API 响应格式的一致性

遵循 REST 原则设计的 API 更加清晰、易用、易维护。


相关链接


rest restful api设计 web开发