CalcGuide · 技术博客主页 / 一页纸学习计划
🔥极高

资源建模与 HTTP 契约:从 URL 到一致的错误和查询

分类:Web 与后端 · 路径:docs/topics/resource-http-contracts/README.md

#rest#api#http#openapi

建立资源、URL、method、状态码、problem+json、分页与过滤的稳定契约

父主题

REST API 设计与实现:从资源建模到可观测 API

子主题(0)

资源建模与 HTTP 契约:从 URL 到一致的错误和查询

0. 元信息

1. 学习路线

资源边界 → URL → method → status → problem+json → cursor/filter/sort

2. 阶段周数分配

精简子主题不固定周数。按 §3 顺序完成,卡住时回到 RFC、契约样例和可重复请求。

3. 九阶段表

阶段核心知识实践产出学会标准
1术语与边界术语表不混淆相邻概念
2HTTP/标准语义请求矩阵能引用规范解释
3数据与状态schema/状态图正常与冲突可区分
4安全边界威胁清单非法路径被拒绝
5失败语义错误目录客户端能稳定处理
6兼容策略变更表能识别 breaking change
7工具验证curl/collection可重复运行
8自动检查契约测试修改后会报警
9小项目可运行交付第三方可复现

4. 第一周任务

精简版省略固定日程。做一个最小正常请求,再补认证失败、非法输入、冲突、重试与超时。

5. 阶段通用验收

精简版省略;每个产出至少保留命令、预期、实际与版本。

6. 最终验收

精简版省略;以 §3 第 9 阶段和 §9.4 问题口述检查为准。

7. 综合项目

精简版省略;成果并入父主题电商商品 / 订单 API。

本主题贡献

交付物清单

  1. openapi/resources.yaml:OpenAPI 3.1 spec,覆盖 /products/products/{productId}/orders/orders/{orderId} ≥ 6 个 operation,包含 components.securitySchemes 引用与 webhooks 段;
  2. openapi/problem.yaml + errors/problem.json:≥ 8 种错误码 + application/problem+json 响应模板(含 errors[].pointer),并落 errors/401.jsonerrors/404.jsonerrors/409.json 等样例;
  3. collection/products.curl + collection/orders.bruno:≥ 20 个可重跑用例,含正常 + 401 / 403 / 404 / 409 / 412 / 422 / 429 / 5xx,make test 一键重跑;
  4. spec/contract_check.md:契约测试(Schemathesis / Dredd / Prism mock)逐 operation 跑通,0 unexpected;附 X-RateLimit-RemainingETagVary 等 header 断言。

验收标准

8. 推荐资料

精简版省略;使用 §9.3 和 §9.6 Source。

9. 学习资料汇聚(v0.3 自包含)

9.1 背景与动机

建立资源、URL、method、状态码、problem+json、分页与过滤的稳定契约。API 一旦被客户端依赖,错误的语义会变成多年兼容成本。我们用规范、可运行样例和失败测试约束选择。

9.2 概念地图

flowchart LR
  Design[设计] --> Contract[HTTP/OpenAPI 契约]
  Contract --> Runtime[实现/网关]
  Runtime --> Client[客户端]
  Runtime --> Evidence[日志/指标/trace]
  Test[契约与失败测试] -.验证.-> Contract
  Test -.验证.-> Runtime

这张图把设计、实现、调用和证据串起来。任何规则都要能落到契约或运行时检查。

9.3 基础知识讲解

9.3.1 论文 / 规范

9.3.2 书

9.3.3 博客 / 文档

9.3.4 人物

9.3.5 方法

9.4 经典问题与经典案例

问题为什么重要最简答案
资源名词化还是动作化影响客户端正确性和长期兼容写清语义、失败码、重试与测试证据
POST/PUT/PATCH 如何选影响客户端正确性和长期兼容写清语义、失败码、重试与测试证据
401/403 如何分影响客户端正确性和长期兼容写清语义、失败码、重试与测试证据
409/412/422 如何分影响客户端正确性和长期兼容写清语义、失败码、重试与测试证据
cursor 如何防重漏影响客户端正确性和长期兼容写清语义、失败码、重试与测试证据
批量操作如何报告部分失败影响客户端正确性和长期兼容写清语义、失败码、重试与测试证据

9.4.1 实战片段:状态码对照、OpenAPI、problem+json

场景状态码含义客户端常见处理
资源不存在,且未确认过404 Not Found路径或 id 没命中不重试;按业务决定是否创建
资源曾经存在但已删除410 Gone永久删除提示用户;从列表里移除
字段语义校验失败422 Unprocessable Entity语法 OK、语义失败展示错误,修正后重提交
状态机/唯一约束冲突409 Conflict当前状态不接受此操作拉最新状态再决定
并发更新 ETag 不匹配412 Precondition Failed资源已被改动重新拉取、合并、二次提交
限流429 Too Many Requests配额或速率触发退避 + Retry-After
openapi: 3.1.0
info:
  title: Shop API
  version: 1.0.0
  description: 商品与订单资源
servers:
  - url: https://api.example.com
paths:
  /products:
    get:
      summary: 列出商品
      parameters:
        - {name: cursor, in: query, schema: {type: string}}
        - {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
        - {name: status, in: query, schema: {type: string, enum: [active, archived]}}
      responses:
        '200':
          description: 商品列表
          headers:
            X-RateLimit-Remaining: {schema: {type: integer}}
          content:
            application/json:
              schema:
                type: object
                required: [data, page]
                properties:
                  data:
                    type: array
                    items: {$ref: '#/components/schemas/Product'}
                  page:
                    type: object
                    properties:
                      nextCursor: {type: [string, "null"]}
              examples:
                ok:
                  value:
                    data:
                      - {id: p_1, name: 茶杯, price: 1200, currency: CNY, etag: W/"abc"}
                    page: {nextCursor: eyJpZCI6InBfMiJ9}
  /products/{productId}:
    parameters:
      - {name: productId, in: path, required: true, schema: {type: string}}
    get:
      responses:
        '200':
          description: 商品详情
          headers:
            ETag: {schema: {type: string}}
          content:
            application/json:
              schema: {$ref: '#/components/schemas/Product'}
        '304': {description: 未变化}
        '404':
          description: 资源不存在
          content:
            application/problem+json:
              schema: {$ref: '#/components/schemas/Problem'}
        '410':
          description: 已删除
          content:
            application/problem+json:
              schema: {$ref: '#/components/schemas/Problem'}
    put:
      parameters:
        - {name: If-Match, in: header, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema: {$ref: '#/components/schemas/ProductUpsert'}
      responses:
        '200':
          description: 替换成功
          headers: {ETag: {schema: {type: string}}}
        '409':
          description: 唯一约束冲突
          content: {application/problem+json: {schema: {$ref: '#/components/schemas/Problem'}}}
        '412': {description: ETag 不匹配(并发冲突)}
        '422':
          description: 字段语义错误
          content:
            application/problem+json:
              schema: {$ref: '#/components/schemas/Problem'}
components:
  schemas:
    Product:
      type: object
      required: [id, name, price, currency]
      properties:
        id: {type: string}
        name: {type: string, minLength: 1, maxLength: 200}
        price: {type: integer, minimum: 0, description: 最小货币单位}
        currency: {type: string, pattern: '^[A-Z]{3}$'}
        etag: {type: string}
    ProductUpsert:
      type: object
      required: [name, price, currency]
      properties:
        name: {type: string, minLength: 1, maxLength: 200}
        price: {type: integer, minimum: 0}
        currency: {type: string, pattern: '^[A-Z]{3}$'}
    Problem:
      type: object
      required: [type, title, status]
      properties:
        type: {type: string, format: uri}
        title: {type: string}
        status: {type: integer}
        detail: {type: string}
        instance: {type: string}
        code: {type: string, description: 稳定业务错误码}
        errors:
          type: array
          items:
            type: object
            properties:
              pointer: {type: string}
              code: {type: string}
              message: {type: string}
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "https://api.example.com/problems/validation-failed",
  "title": "Validation failed",
  "status": 422,
  "detail": "请求体字段不通过校验",
  "instance": "/products/p_1",
  "code": "validation_failed",
  "errors": [
    {"pointer": "/price", "code": "min_value", "message": "must be >= 0"},
    {"pointer": "/currency", "code": "pattern", "message": "must match ^[A-Z]{3}$"}
  ]
}
# curl:条件 GET 与并发更新
curl -i https://api.example.com/products/p_1
curl -i -H 'If-None-Match: W/"abc"' https://api.example.com/products/p_1

curl -i -X PUT https://api.example.com/products/p_1 \
  -H 'Content-Type: application/json' \
  -H 'If-Match: W/"abc"' \
  -d '{"name":"茶杯","price":1300,"currency":"CNY"}'

# 幂等创建:同 key 不重复扣款
curl -i -X POST https://api.example.com/orders \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 9f2b6c1a-1f3d-4b8e-9b6c-2a7f0b5c91a2' \
  -d '{"productId":"p_1","quantity":2}'

9.5 学习难点

9.6 技术标准与接口

9.6.1 Entity

名称版本组织状态 / 可访问性
OpenAPI Specification3.1OpenAPI Initiative正式;Apache-2.0 仓库,规范公开
JSON:API1.1JSON:API 社区正式;公开
JSON Schema2020-12JSON Schema / IETF 社区正式;公开
Problem Details for HTTP APIsRFC 7807IETF已被 RFC 9457 更新;RFC 公开
HALdraft-kelly-json-halIETF Internet-Draft / HAL 社区草案;公开

9.6.2 Scope

OpenAPI 描述 HTTP API;JSON Schema 描述数据约束;JSON:API 与 HAL 约定表示和链接;Problem Details 约定机器可读错误。它们不替代业务授权、事务设计或运行时保护。

9.6.3 Structure

OpenAPI 必会 pathsoperationsparametersrequestBodyresponsescomponentssecuritySchemes;JSON Schema 必会 typerequiredproperties、组合与引用;Problem Details 必会 type/title/status/detail/instance

9.6.4 Ecosystem

实现与工具包括 Swagger UI、Redoc、Spectral、OpenAPI Generator、Postman、Insomnia、Bruno、httpie、curl。API gateway 常用 Apigee、AWS API Gateway、Kong、Envoy。工具默认值不是规范。

9.6.5 Depth Tiers

层级可观察能力
L0知道这些标准解决什么问题
L1看懂 schema、operation 和 problem body
L2能正确编写、校验、生成客户端并调用
L3能解释语义、排错兼容/鉴权/缓存/限流问题
L4能设计扩展、治理规则与跨团队演进机制

本计划目标:L3

9.6.6 Source

10. 常见误区

11. 所有知识点分类(统一规则)

  1. 编程语言 2. 数据结构与算法 3. 计算机基础 4. 工程技术 5. Web 与后端 6. 前端与客户端 7. 数据与人工智能 8. 项目与职业能力 9. 安全与可靠性

本计划归属:Web 与后端 主 + 工程技术 辅。

直接依赖(0)

查看知识图谱 · 热度 🔥极高