菜单设计学——从阿明的“口头点单“到标准化菜单,看 API 设计的艺术与科学

菜单设计学——从阿明的“口头点单“到标准化菜单,看 API 设计的艺术与科学 系列定位本篇是「阿明餐厅」系列的正传 6。在前传中阿明将系统拆分为微服务在从厨师到 CEO中团队通过 API 契约协作。但API 本身怎么设计这是微服务架构和跨团队协作的基础。引言口头点单的混乱阿明的餐厅最初没有菜单顾客口头点单“来碗面加个蛋不要葱。”问题是字迹潦草后厨看不懂接口不规范、“加个蛋理解成加两个蛋”歧义、新服务员不知道备注格式缺少文档、后厨改了菜名前厅不知道接口变更不兼容。API 设计的本质不是定义接口而是定义团队之间的沟通契约。好的 API 设计让调用方一看就懂、一用就会、一改就知。第一章RESTful API —— 标准化菜单RESTRepresentational State Transfer是目前最主流的 API 设计风格。核心思想把后端数据抽象为资源用 HTTP 方法操作资源。REST 的核心原则原则说明示例资源导向URL 表示资源而非操作/orders/123而非/getOrder?id123HTTP 方法语义化GET 查询、POST 创建、PUT 更新、DELETE 删除GET /orders/123状态码标准化200 成功、404 不存在、500 服务器错误订单不存在返回 404无状态每个请求携带完整信息每次请求带 Token阿明的 RESTful 菜单GET /orders # 查询订单列表 POST /orders # 创建新订单 GET /orders/{id} # 查询订单详情 PUT /orders/{id} # 更新订单全量 PATCH /orders/{id} # 更新订单部分 DELETE /orders/{id} # 删除订单 GET /orders/{id}/items # 查询订单的菜品明细REST 的反模式反模式 1URL 中用动词。POST /createOrder不如POST /orders因为 HTTP 方法本身已经表达了操作语义。反模式 2忽略状态码。所有响应都返回 200错误信息在 body 中 —— 这让调用方无法通过 HTTP 状态码快速判断请求结果。REST 的核心是资源导向 语义化。设计时问自己“这个 URL 表示什么资源用什么 HTTP 方法操作”第二章版本管理 —— 菜单升级老顾客怎么办阿明想把牛肉面改名为秘制牛肉面价格从 28 涨到 38 元。直接改名会导致老顾客找不到、投诉涨价不通知接口变更不兼容。API 版本管理的核心是新版本上线时老版本继续可用给调用方迁移时间。三种版本管理策略策略实现方式优缺点URL 版本/v1/ordersvs/v2/orders直观但 URL 冗余Header 版本Accept: application/vnd.restaurant.v1jsonURL 干净但不直观参数版本/orders?version1vs/orders?version2灵活但参数污染阿明选择了URL 版本因为最直观。向后兼容原则向后兼容的变更不需要升版本新增可选字段、新增接口。不向后兼容的变更必须升版本删除字段、修改字段类型、修改字段语义、修改 URL 路径。阿明的策略所有不向后兼容的变更必须升版本老版本至少保留 6 个月。向后兼容也是灰度发布的前提 —— 新旧版本必须能同时运行。第三章REST vs gRPC vs GraphQL —— 三种菜单风格阿明的餐厅有三种点单方式标准菜单REST按固定菜单点、定制菜单GraphQL自由组合配料、快速点单gRPCVIP 专属通道。三种 API 风格对比特性RESTGraphQLgRPC协议HTTP/1.1HTTP/1.1HTTP/2数据格式JSONJSONProtocol Buffers二进制查询方式固定端点固定字段单一端点客户端指定字段固定端点固定字段性能中中高二进制 流式学习成本低中高适用场景通用 API、对外 API前端灵活查询、移动端微服务间通信、高性能GraphQL解决 Over/Under-fetching# 客户端指定需要的字段避免 Over-fetching query { order(id: 123) { id dish price # 不需要 user 信息就不返回 } } # 一次请求获取订单 菜品明细避免 Under-fetching query { order(id: 123) { id items { name, quantity } } }GraphQL 的优点是灵活缺点是缓存困难、复杂查询可能拖慢数据库。gRPC高性能的内部通信gRPC 使用 Protocol Buffers 定义接口编译时自动检查类型像调用本地函数一样调用远程服务。优点是高性能二进制序列化、HTTP/2 多路复用缺点是浏览器支持差、调试困难。阿明的选择场景选择原因对外 API给第三方REST生态成熟文档友好前端 APIWeb/AppGraphQL灵活查询减少请求次数微服务间通信gRPC高性能强类型API 风格没有最好只有最适合。值得一提的是AI Agent 的 Function Calling本质上也是标准化 API 设计的应用 —— 智能体通过 JSON Schema 定义工具接口和 RESTful 的资源导向思路一脉相承。第四章API 文档 —— 菜单要有说明阿明的菜单设计好了但顾客看不懂“招牌牛肉面’和’秘制牛肉面’有什么区别”OpenAPI原 Swagger是目前最流行的 API 文档标准。它用 YAML 或 JSON 描述 API自动生成文档和客户端代码。openapi:3.0.0info:title:阿明餐厅 APIversion:1.0.0paths:/v1/orders/{id}:get:summary:查询订单详情parameters:-name:idin:pathrequired:trueschema:type:stringresponses:200:description:查询成功404:description:订单不存在API 文档的最佳实践原则说明示例驱动每个接口都有请求/响应示例可直接复制使用错误码说明列出所有可能的错误码和含义变更记录每次 API 变更都记录在 Changelog 中在线测试提供 Swagger UI调用方可直接测试接口反模式文档和实现不同步。阿明最初的文档是手动编写的 Markdown后端改了接口忘记更新文档。策略用 OpenAPI 自动生成文档文档和代码一起提交保证同步更新。这和从厨师到 CEO 中的 API 契约是同一思路 —— 契约必须可验证、可追踪。第五章错误处理 —— 菜单要标注过敏原阿明的菜单上有一道菜花生牛肉面但没有标注含花生。顾客对花生过敏吃完后进了医院。API 错误处理的核心是让调用方知道哪里出错了、为什么出错、怎么处理。错误响应设计// 好的错误响应信息完整{error:{code:INSUFFICIENT_STOCK,message:库存不足无法创建订单,details:{dish_name:牛肉面,requested_quantity:5,available_quantity:3},request_id:req_abc123,documentation_url:https://api.restaurant.com/docs/errors#INSUFFICIENT_STOCK}}常见错误码错误码HTTP 状态码含义INVALID_PARAMETER400参数错误UNAUTHORIZED401未认证NOT_FOUND404资源不存在INSUFFICIENT_STOCK409库存不足RATE_LIMIT_EXCEEDED429请求频率超限详见限流INTERNAL_ERROR500服务器内部错误幂等性避免重复提交顾客点击下单按钮两次系统创建了两个订单。幂等性Idempotency的核心是同一个请求执行多次结果和执行一次相同。POST /v1/orders Idempotency-Key: order_123_20240528_120000 # 第一次请求创建订单返回 201 # 第二次请求相同的 Idempotency-Key返回已创建的订单返回 200阿明的策略所有写操作POST/PUT/DELETE都要支持幂等性通过Idempotency-Key避免重复执行。第六章API 网关 —— 统一入口统一管理阿明有 10 个服务如果每个都暴露独立域名调用方要记住 10 个地址。API 网关API Gateway的核心是提供统一入口屏蔽后端服务的复杂性。客户端请求 ↓ API 网关 1. 认证授权验证 Token详见[安全架构](./06-security-architecture.md) 2. 限流熔断控制请求频率详见[高峰保卫战](./04-peak-traffic-defense.md) 3. 路由转发根据 URL 路由到后端服务 4. 协议转换外部 REST → 内部 gRPC 5. 日志监控记录请求日志详见[厨房装监控](./05-observability.md) ↓ 后端服务订单、支付、菜品……价值说明统一入口调用方只需要记住一个地址集中管理认证、限流、监控等横切关注点集中处理协议转换外部 REST内部 gRPC网关负责转换反模式网关成为单点故障。阿明的策略网关至少 3 个实例高可用部署、检测到后端故障直接返回降级响应、性能指标实时监控。API 网关的核心是统一入口 集中管理。没有网关微服务架构就是一场混乱。核心总结API 设计的艺术与科学API 设计RESTful 风格资源导向 语义化版本管理向后兼容 平滑迁移风格选择REST / GraphQL / gRPC文档规范OpenAPI 自动生成错误处理信息完整 幂等性API 网关统一入口 集中管理设计原则核心问题餐厅类比技术实现RESTful怎么定义资源标准化菜单URL 表示资源HTTP 方法操作版本管理怎么平滑升级菜单升级老顾客怎么办URL 版本/v1/ vs /v2/风格选择REST / GraphQL / gRPC 怎么选标准 / 定制 / 快速点单根据场景选择文档规范怎么让调用方一看就懂菜单要有说明OpenAPI / Swagger错误处理怎么让调用方知道哪里出错菜单标注过敏原错误码 幂等性API 网关怎么统一管理统一入口Kong / Nginx / AWS API Gateway一句心法API 设计不是定义接口而是定义团队之间的沟通契约。好的 API 设计让调用方一看就懂、一用就会、一改就知。RESTful 是基础版本管理是保障文档是桥梁网关是入口。延伸阅读从厨师到 CEO —— API 契约是跨团队协作的基础API 设计是契约的核心架构是长出来的 —— 微服务拆分后API 设计成为系统间通信的核心挑战从接单到出餐 —— 部署新版本时API 向后兼容是灰度发布的前提高峰保卫战 —— API 网关的限流、熔断能力是流量治理的第一道防线厨房装监控 —— API 网关的日志、指标、追踪是可观测性的数据来源食安大检查 —— API 网关的认证、授权、数据脱敏是安全架构的核心环节厨房质检员 —— 契约测试验证 API 的向后兼容性是 API 变更的质量保障当餐厅长出大脑 —— Function Calling 的标准化接口设计是 API 设计在 AI 领域的应用给产品经理的重构说明书 —— 重构过程中API 的向后兼容是绞杀者模式的核心保障结语阿明从口头点单到标准化菜单的故事本质上是所有微服务架构都要面对的问题怎么设计好的 API让团队之间高效协作而不是靠口头沟通和人情答案是 RESTful 版本管理 文档规范 错误处理 API 网关RESTful 让接口语义化版本管理保证向后兼容文档让调用方一看就懂错误处理让调用方知道哪里出错API 网关提供统一入口。下次当你设计 API 时不妨问自己我的 API 是 RESTful 的吗URL 表示资源HTTP 方法操作资源我有版本管理吗新版本上线时老版本继续可用我选择了合适的 API 风格吗REST / GraphQL / gRPC 根据场景选择错误处理完整吗错误码、错误信息、幂等性都考虑到了我有 API 网关吗统一入口、集中管理认证/限流/监控好的 API不是让后端写起来方便而是让调用方用起来方便。一看就懂、一用就会、一改就知。← 返回系列导读