资源设计 #
什么是资源? #
在 REST 架构中,资源是核心概念。资源是任何可以被命名和引用的信息实体。
text
┌─────────────────────────────────────────────────────────────┐
│ 资源定义 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 资源 = 任何可以被命名的事物 │
│ │
│ 可以是: │
│ - 实体对象:用户、商品、订单 │
│ - 集合:用户列表、商品目录 │
│ - 虚拟概念:搜索结果、报表 │
│ - 业务流程:支付、审批 │
│ │
│ 关键特征: │
│ ✅ 有唯一标识(URI) │
│ ✅ 有状态数据(表述) │
│ ✅ 可被操作(CRUD) │
│ │
└─────────────────────────────────────────────────────────────┘
资源识别 #
识别方法 #
text
┌─────────────────────────────────────────────────────────────┐
│ 资源识别步骤 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 第一步:分析业务领域 │
│ ───────────────────────────────────────────── │
│ - 系统中有哪些核心实体? │
│ - 实体之间的关系是什么? │
│ - 哪些需要对外暴露? │
│ │
│ 示例:电商系统 │
│ - 用户(User) │
│ - 商品(Product) │
│ - 订单(Order) │
│ - 购物车(Cart) │
│ - 评论(Review) │
│ │
│ 第二步:确定资源类型 │
│ ───────────────────────────────────────────── │
│ - 集合资源:多个资源的集合 │
│ - 单个资源:特定标识的资源 │
│ - 子资源:属于其他资源的资源 │
│ │
│ 第三步:定义资源属性 │
│ ───────────────────────────────────────────── │
│ - 标识属性:id │
│ - 业务属性:name, email, price │
│ - 元数据:createdAt, updatedAt │
│ │
└─────────────────────────────────────────────────────────────┘
资源类型详解 #
text
┌─────────────────────────────────────────────────────────────┐
│ 资源类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 集合资源(Collection Resource) │
│ ───────────────────────────────────────────── │
│ 定义:一组相同类型资源的集合 │
│ │
│ URI:/users │
│ │
│ 操作: │
│ GET /users 获取用户列表 │
│ POST /users 创建新用户 │
│ │
│ 2. 单个资源(Singleton Resource) │
│ ───────────────────────────────────────────── │
│ 定义:集合中的一个具体资源 │
│ │
│ URI:/users/123 │
│ │
│ 操作: │
│ GET /users/123 获取指定用户 │
│ PUT /users/123 更新用户 │
│ DELETE /users/123 删除用户 │
│ │
│ 3. 子资源(Sub-resource) │
│ ───────────────────────────────────────────── │
│ 定义:属于另一个资源的资源 │
│ │
│ URI:/users/123/orders │
│ │
│ 操作: │
│ GET /users/123/orders 获取用户订单 │
│ POST /users/123/orders 为用户创建订单 │
│ │
│ 4. 单例子资源(Singleton Sub-resource) │
│ ───────────────────────────────────────────── │
│ 定义:一对一关系的子资源 │
│ │
│ URI:/users/123/profile │
│ │
│ 操作: │
│ GET /users/123/profile 获取用户资料 │
│ PUT /users/123/profile 更新用户资料 │
│ │
└─────────────────────────────────────────────────────────────┘
资源命名 #
命名规则 #
text
┌─────────────────────────────────────────────────────────────┐
│ 资源命名规则 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 规则一:使用名词 │
│ ───────────────────────────────────────────── │
│ ✅ /users │
│ ✅ /products │
│ ❌ /getUsers │
│ ❌ /createProduct │
│ │
│ 规则二:使用复数形式 │
│ ───────────────────────────────────────────── │
│ ✅ /users │
│ ✅ /orders │
│ ❌ /user │
│ ❌ /order │
│ │
│ 规则三:使用小写字母 │
│ ───────────────────────────────────────────── │
│ ✅ /user-profiles │
│ ✅ /order-items │
│ ❌ /UserProfiles │
│ ❌ /OrderItems │
│ │
│ 规则四:使用连字符分隔 │
│ ───────────────────────────────────────────── │
│ ✅ /order-items │
│ ✅ /user-profiles │
│ ❌ /orderItems │
│ ❌ /user_profiles │
│ │
│ 规则五:避免文件扩展名 │
│ ───────────────────────────────────────────── │
│ ✅ /users/123 │
│ ❌ /users/123.json │
│ ❌ /users/123.xml │
│ │
│ 规则六:避免尾部斜杠 │
│ ───────────────────────────────────────────── │
│ ✅ /users │
│ ❌ /users/ │
│ │
└─────────────────────────────────────────────────────────────┘
命名示例 #
text
┌─────────────────────────────────────────────────────────────┐
│ 命名示例对照 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 业务场景 错误命名 正确命名 │
│ ───────────────────────────────────────────────────────── │
│ 用户管理 /user /users │
│ /getUsers /users │
│ /User /users │
│ │
│ 订单管理 /order /orders │
│ /orderList /orders │
│ /get-order-list /orders │
│ │
│ 订单项 /orderItem /order-items │
│ /order_items /order-items │
│ /OrderItem /order-items │
│ │
│ 用户资料 /userProfile /user-profiles │
│ /user_profile /user-profiles │
│ /UserProfile /user-profiles │
│ │
│ 购物车 /cart /carts │
│ /shopping-cart /carts │
│ /ShoppingCart /carts │
│ │
└─────────────────────────────────────────────────────────────┘
资源层级设计 #
层级结构 #
text
┌─────────────────────────────────────────────────────────────┐
│ 资源层级结构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 第一层:顶级资源 │
│ /users │
│ /products │
│ /orders │
│ │
│ 第二层:子资源 │
│ /users/123/orders │
│ /products/456/reviews │
│ /orders/789/items │
│ │
│ 第三层:更深层级(谨慎使用) │
│ /users/123/orders/789/items │
│ │
│ 建议: │
│ - 层级不超过 3 层 │
│ - 过深层级考虑使用查询参数 │
│ - 复杂关系考虑独立资源 │
│ │
└─────────────────────────────────────────────────────────────┘
层级设计示例 #
text
┌─────────────────────────────────────────────────────────────┐
│ 层级设计示例 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 场景:电商系统 │
│ │
│ 用户资源层级: │
│ /users 用户集合 │
│ /users/123 单个用户 │
│ /users/123/orders 用户订单 │
│ /users/123/orders/456 单个订单 │
│ /users/123/profile 用户资料 │
│ /users/123/addresses 用户地址 │
│ /users/123/addresses/1 单个地址 │
│ │
│ 商品资源层级: │
│ /products 商品集合 │
│ /products/456 单个商品 │
│ /products/456/reviews 商品评论 │
│ /products/456/images 商品图片 │
│ /products/456/variants 商品变体 │
│ │
│ 订单资源层级: │
│ /orders 订单集合 │
│ /orders/789 单个订单 │
│ /orders/789/items 订单项 │
│ /orders/789/items/1 单个订单项 │
│ /orders/789/payments 支付记录 │
│ │
└─────────────────────────────────────────────────────────────┘
层级设计决策 #
text
┌─────────────────────────────────────────────────────────────┐
│ 层级设计决策指南 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 问题:如何表示资源之间的关系? │
│ │
│ 方案一:嵌套资源(子资源) │
│ ───────────────────────────────────────────── │
│ 适用场景: │
│ - 子资源完全属于父资源 │
│ - 子资源没有独立存在的意义 │
│ - 通常通过父资源访问 │
│ │
│ 示例: │
│ /users/123/orders 用户的订单 │
│ /orders/789/items 订单的订单项 │
│ │
│ 方案二:独立资源 + 关联 │
│ ───────────────────────────────────────────── │
│ 适用场景: │
│ - 资源可以独立存在 │
│ - 资源有多种访问方式 │
│ - 需要直接访问资源 │
│ │
│ 示例: │
│ /orders/789 直接访问订单 │
│ /orders/789?user_id=123 通过用户过滤订单 │
│ /users/123/orders 通过用户访问订单 │
│ │
│ 方案三:使用查询参数 │
│ ───────────────────────────────────────────── │
│ 适用场景: │
│ - 避免层级过深 │
│ - 灵活过滤 │
│ │
│ 示例: │
│ /comments?user_id=123&post_id=456 │
│ │
└─────────────────────────────────────────────────────────────┘
资源标识设计 #
ID 设计 #
text
┌─────────────────────────────────────────────────────────────┐
│ 资源标识设计 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 常见 ID 类型: │
│ │
│ 1. 自增整数 │
│ /users/1 │
│ /users/2 │
│ │
│ 优点:简单、有序、易读 │
│ 缺点:可预测、暴露业务量 │
│ │
│ 2. UUID │
│ /users/550e8400-e29b-41d4-a716-446655440000 │
│ │
│ 优点:不可预测、全局唯一 │
│ 缺点:较长、不美观 │
│ │
│ 3. 雪花算法 ID │
│ /users/1234567890123456789 │
│ │
│ 优点:有序、分布式唯一 │
│ 缺点:较长 │
│ │
│ 4. 自定义 ID │
│ /products/iPhone-15-pro │
│ /posts/how-to-design-api │
│ │
│ 优点:语义化、SEO 友好 │
│ 缺点:可能冲突、变更困难 │
│ │
│ 推荐: │
│ - 内部系统:自增整数或雪花 ID │
│ - 公开 API:UUID 或自定义 ID │
│ │
└─────────────────────────────────────────────────────────────┘
URI 模板 #
text
┌─────────────────────────────────────────────────────────────┐
│ URI 模板 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 基本格式: │
│ /{resource}/{id} │
│ /{resource}/{id}/{sub-resource} │
│ /{resource}/{id}/{sub-resource}/{sub-id} │
│ │
│ 示例: │
│ /users 用户集合 │
│ /users/{userId} 单个用户 │
│ /users/{userId}/orders 用户订单集合 │
│ /users/{userId}/orders/{orderId} 单个订单 │
│ │
│ 参数命名: │
│ - 使用 camelCase:userId, orderId │
│ - 语义清晰:productId, commentId │
│ - 避免缩写:userId 而非 uid │
│ │
└─────────────────────────────────────────────────────────────┘
资源表述设计 #
表述格式 #
text
┌─────────────────────────────────────────────────────────────┐
│ 资源表述格式 │
├─────────────────────────────────────────────────────────────┤
│ │
│ JSON 格式(推荐): │
│ { │
│ "id": 123, │
│ "name": "张三", │
│ "email": "zhangsan@example.com", │
│ "status": "active", │
│ "createdAt": "2025-01-15T10:30:00Z", │
│ "updatedAt": "2025-03-20T15:45:00Z" │
│ } │
│ │
│ XML 格式: │
│ <?xml version="1.0"?> │
│ <user> │
│ <id>123</id> │
│ <name>张三</name> │
│ <email>zhangsan@example.com</email> │
│ </user> │
│ │
│ 推荐:使用 JSON 格式 │
│ - 轻量级 │
│ - 易于解析 │
│ - 广泛支持 │
│ │
└─────────────────────────────────────────────────────────────┘
属性命名规范 #
text
┌─────────────────────────────────────────────────────────────┐
│ 属性命名规范 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 规则一:使用 camelCase │
│ ✅ { "firstName": "张", "lastName": "三" } │
│ ❌ { "first_name": "张", "last_name": "三" } │
│ ❌ { "FirstName": "张", "LastName": "三" } │
│ │
│ 规则二:语义清晰 │
│ ✅ { "createdAt": "...", "updatedAt": "..." } │
│ ❌ { "ca": "...", "ua": "..." } │
│ │
│ 规则三:一致性 │
│ ✅ 统一使用 "id" 或 "_id" │
│ ✅ 统一使用 "createdAt" 或 "created_at" │
│ │
│ 规则四:避免冗余 │
│ ✅ { "name": "张三" } │
│ ❌ { "userName": "张三" } // 在用户资源中 │
│ │
│ 规则五:布尔值使用 is/has 前缀 │
│ ✅ { "isActive": true, "hasPermission": false } │
│ ❌ { "active": true, "permission": false } │
│ │
└─────────────────────────────────────────────────────────────┘
标准属性 #
text
┌─────────────────────────────────────────────────────────────┐
│ 标准属性 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 标识属性: │
│ id string/number 资源唯一标识 │
│ │
│ 时间属性: │
│ createdAt string 创建时间(ISO 8601) │
│ updatedAt string 更新时间(ISO 8601) │
│ deletedAt string 删除时间(软删除) │
│ │
│ 状态属性: │
│ status string 资源状态 │
│ isActive boolean 是否激活 │
│ │
│ 统计属性: │
│ totalCount number 总数 │
│ pageCount number 页数 │
│ │
│ 示例: │
│ { │
│ "id": 123, │
│ "name": "张三", │
│ "email": "zhangsan@example.com", │
│ "status": "active", │
│ "isActive": true, │
│ "createdAt": "2025-01-15T10:30:00Z", │
│ "updatedAt": "2025-03-20T15:45:00Z" │
│ } │
│ │
└─────────────────────────────────────────────────────────────┘
资源关系设计 #
关系类型 #
text
┌─────────────────────────────────────────────────────────────┐
│ 资源关系类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 一对一(One-to-One) │
│ ───────────────────────────────────────────── │
│ 示例:用户 - 用户资料 │
│ │
│ /users/123 │
│ /users/123/profile │
│ │
│ 表述: │
│ { │
│ "id": 123, │
│ "name": "张三", │
│ "profile": { │
│ "avatar": "https://...", │
│ "bio": "..." │
│ } │
│ } │
│ │
│ 2. 一对多(One-to-Many) │
│ ───────────────────────────────────────────── │
│ 示例:用户 - 订单 │
│ │
│ /users/123 │
│ /users/123/orders │
│ │
│ 表述: │
│ { │
│ "id": 123, │
│ "name": "张三", │
│ "orders": [ │
│ { "id": 1, "total": 100 }, │
│ { "id": 2, "total": 200 } │
│ ] │
│ } │
│ │
│ 3. 多对多(Many-to-Many) │
│ ───────────────────────────────────────────── │
│ 示例:学生 - 课程 │
│ │
│ /students/123/courses │
│ /courses/456/students │
│ │
│ 表述: │
│ { │
│ "id": 123, │
│ "name": "张三", │
│ "courses": [ │
│ { "id": 1, "name": "数学", "enrolledAt": "..." }, │
│ { "id": 2, "name": "英语", "enrolledAt": "..." } │
│ ] │
│ } │
│ │
└─────────────────────────────────────────────────────────────┘
关联资源处理 #
text
┌─────────────────────────────────────────────────────────────┐
│ 关联资源处理策略 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 策略一:嵌入资源(Embedding) │
│ ───────────────────────────────────────────── │
│ 适用:关联数据量小、频繁一起使用 │
│ │
│ GET /orders/789 │
│ { │
│ "id": 789, │
│ "total": 1000, │
│ "user": { │
│ "id": 123, │
│ "name": "张三" │
│ } │
│ } │
│ │
│ 策略二:资源引用(Reference) │
│ ───────────────────────────────────────────── │
│ 适用:关联数据量大、独立访问 │
│ │
│ GET /orders/789 │
│ { │
│ "id": 789, │
│ "total": 1000, │
│ "userId": 123, │
│ "user": { │
│ "href": "/users/123" │
│ } │
│ } │
│ │
│ 策略三:按需嵌入(Conditional Embedding) │
│ ───────────────────────────────────────────── │
│ 适用:灵活控制返回内容 │
│ │
│ GET /orders/789?embed=user │
│ { │
│ "id": 789, │
│ "total": 1000, │
│ "user": { │
│ "id": 123, │
│ "name": "张三" │
│ } │
│ } │
│ │
│ GET /orders/789 │
│ { │
│ "id": 789, │
│ "total": 1000, │
│ "userId": 123 │
│ } │
│ │
└─────────────────────────────────────────────────────────────┘
资源设计示例 #
电商系统资源设计 #
text
┌─────────────────────────────────────────────────────────────┐
│ 电商系统资源设计 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用户资源: │
│ GET /users 获取用户列表 │
│ POST /users 创建用户 │
│ GET /users/{id} 获取用户详情 │
│ PUT /users/{id} 更新用户 │
│ DELETE /users/{id} 删除用户 │
│ GET /users/{id}/orders 获取用户订单 │
│ GET /users/{id}/addresses 获取用户地址 │
│ GET /users/{id}/profile 获取用户资料 │
│ │
│ 商品资源: │
│ GET /products 获取商品列表 │
│ POST /products 创建商品 │
│ GET /products/{id} 获取商品详情 │
│ PUT /products/{id} 更新商品 │
│ DELETE /products/{id} 删除商品 │
│ GET /products/{id}/reviews 获取商品评论 │
│ GET /products/{id}/variants 获取商品变体 │
│ │
│ 订单资源: │
│ GET /orders 获取订单列表 │
│ POST /orders 创建订单 │
│ GET /orders/{id} 获取订单详情 │
│ PUT /orders/{id} 更新订单 │
│ DELETE /orders/{id} 取消订单 │
│ GET /orders/{id}/items 获取订单项 │
│ POST /orders/{id}/payments 创建支付 │
│ │
│ 购物车资源: │
│ GET /carts 获取购物车列表 │
│ POST /carts 创建购物车 │
│ GET /carts/{id} 获取购物车详情 │
│ PUT /carts/{id} 更新购物车 │
│ DELETE /carts/{id} 清空购物车 │
│ POST /carts/{id}/items 添加商品到购物车 │
│ DELETE /carts/{id}/items/{itemId} 移除购物车商品 │
│ │
└─────────────────────────────────────────────────────────────┘
资源设计检查清单 #
text
□ 资源识别
□ 识别了所有核心业务实体
□ 确定了资源类型(集合/单个/子资源)
□ 定义了资源属性
□ 资源命名
□ 使用名词
□ 使用复数形式
□ 使用小写字母
□ 使用连字符分隔
□ 无文件扩展名
□ 无尾部斜杠
□ 资源层级
□ 层级不超过 3 层
□ 关系表达清晰
□ 避免过度嵌套
□ 资源标识
□ 选择合适的 ID 类型
□ URI 模板清晰
□ 资源表述
□ 使用 JSON 格式
□ 属性命名规范
□ 包含标准属性
□ 关联资源处理合理
下一步 #
现在你已经了解了资源设计的方法,接下来学习 端点设计,深入了解如何设计完整的 API 端点!
最后更新:2026-03-29