API设计Skill api-design

API设计技能专注于设计和构建高效、可扩展的API接口,包括RESTful API、GraphQL模式和gRPC服务,适用于软件开发和系统集成场景。关键词:API设计,REST,GraphQL,gRPC,OpenAPI,Swagger,接口设计,软件架构,后端开发。

架构设计 0 次安装 0 次浏览 更新于 3/24/2026

name: api-design description: 遵循最佳实践设计RESTful API、GraphQL模式和RPC接口,以确保一致性、可用性和可扩展性。触发关键词:api设计,REST,RESTful,REST API,GraphQL,GraphQL模式,gRPC,OpenAPI,Swagger,端点,路由,资源,CRUD,HTTP方法,GET,POST,PUT,PATCH,DELETE,状态码,分页,过滤,排序,版本控制,HATEOAS,API版本控制,模式设计,RPC,服务设计。 allowed-tools: Read, Grep, Glob, Edit, Write

API设计

概述

本技能指导设计结构良好、直观、一致且可扩展的API。它涵盖REST、GraphQL和gRPC模式,重点在于开发者体验和长期可维护性。

指令

1. 理解需求

  • 识别API消费者和用例
  • 定义资源模型和关系
  • 确定认证/授权需求
  • 规划版本控制策略

2. 设计资源结构

  • 定义清晰的资源层次结构
  • 建立命名约定
  • 规划URL模式
  • 设计请求/响应模式

3. 定义操作

  • 将CRUD操作映射到HTTP方法
  • 设计查询参数进行过滤/排序
  • 规划分页方法
  • 定义错误响应格式

4. 文档化API

  • 创建OpenAPI/Swagger规范
  • 包含所有端点的示例
  • 文档化认证流程
  • 提供SDK使用示例

最佳实践

RESTful API设计

  1. 使用名词作为资源/users,而不是/getUsers
  2. 一致的命名:在所有端点中一致使用snake_case或camelCase
  3. 正确的HTTP方法
    • GET(读取/获取),POST(创建),PUT(完全更新),PATCH(部分更新),DELETE(删除)
  4. 有意义的状态码
    • 200(OK),201(Created),204(No Content)
    • 400(Bad Request),401(Unauthorized),403(Forbidden),404(Not Found)
    • 409(Conflict),422(Unprocessable Entity)
    • 500(Internal Server Error),503(Service Unavailable)
  5. 幂等性:PUT和DELETE应该是幂等的;考虑为POST使用幂等键
  6. HATEOAS:在响应中包含相关资源的链接
  7. 过滤与排序:使用查询参数(?status=active&sort=-created_at
  8. 分页:大数据集使用基于游标的分页,简单情况使用偏移分页

GraphQL模式设计

  1. 使用描述性类型:清晰、自文档化的类型和字段名
  2. 连接模式:使用relay-style连接进行分页列表
  3. 输入对象:为变体分离输入类型(CreateUserInput,UpdateUserInput)
  4. 错误处理:将错误作为负载的一部分返回,而不仅仅是顶级异常
  5. 可空性:明确可空与非可空字段
  6. 变体返回负载:在变体响应中包括数据和错误
  7. 避免过度获取:设计片段和字段以匹配常见查询模式

gRPC服务设计

  1. 服务命名:为RPC方法使用动词(CreateUser,GetUser,ListUsers)
  2. 消息重用:为常见模式定义共享消息类型
  3. 分页:使用page_token模式进行基于游标的分页
  4. 错误:使用google.rpc.Status提供丰富的错误详情
  5. 版本控制:使用包版本控制(myapi.v1,myapi.v2)
  6. 流式传输:在适当情况下利用服务器/客户端/双向流式传输

API版本控制策略

  1. URL路径版本控制/v1/users/v2/users(显式、简单、可缓存)
  2. 头部版本控制API-Version: 2Accept: application/vnd.api.v2+json(URL更简洁)
  3. 查询参数版本控制?version=2(备用选项,不太推荐)
  4. 语义版本控制:主版本用于破坏性更改,次版本用于功能,补丁用于修复
  5. 弃用政策:宣布日落日期,至少支持N-1个版本

示例

示例1:RESTful资源设计

# OpenAPI 3.0 规范
openapi: 3.0.0
info:
  title: 电子商务API
  version: 1.0.0

paths:
  /products:
    get:
      summary: 列出所有产品
      parameters:
        - name: category
          in: query
          schema:
            type: string
        - name: min_price
          in: query
          schema:
            type: number
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: per_page
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        "200":
          description: 分页的产品列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Product"
                  pagination:
                    $ref: "#/components/schemas/Pagination"

    post:
      summary: 创建新产品
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductInput"
      responses:
        "201":
          description: 产品已创建
        "400":
          description: 验证错误

  /products/{id}:
    get:
      summary: 获取特定产品
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: 产品详情
        "404":
          description: 产品未找到

示例2:GraphQL模式设计

type Query {
  """
  通过ID获取用户
  """
  user(id: ID!): User

  """
  列出用户,可选过滤
  """
  users(filter: UserFilter, first: Int = 20, after: String): UserConnection!
}

type Mutation {
  """
  创建新用户账户
  """
  createUser(input: CreateUserInput!): CreateUserPayload!

  """
  更新现有用户
  """
  updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
}

type User {
  id: ID!
  email: String!
  name: String!
  createdAt: DateTime!
  orders(first: Int, after: String): OrderConnection!
}

input CreateUserInput {
  email: String!
  name: String!
  password: String!
}

type CreateUserPayload {
  user: User
  errors: [UserError!]!
}

type UserError {
  field: String
  message: String!
  code: UserErrorCode!
}

示例3:gRPC服务定义

syntax = "proto3";

package ecommerce.v1;

import "google/protobuf/timestamp.proto";

service ProductService {
  // 通过ID获取单个产品
  rpc GetProduct(GetProductRequest) returns (GetProductResponse);

  // 列出产品,带过滤和分页
  rpc ListProducts(ListProductsRequest) returns (ListProductsResponse);

  // 创建新产品
  rpc CreateProduct(CreateProductRequest) returns (CreateProductResponse);

  // 更新现有产品
  rpc UpdateProduct(UpdateProductRequest) returns (UpdateProductResponse);

  // 删除产品
  rpc DeleteProduct(DeleteProductRequest) returns (DeleteProductResponse);
}

message Product {
  string id = 1;
  string name = 2;
  string description = 3;
  int64 price_cents = 4;
  string category = 5;
  google.protobuf.Timestamp created_at = 6;
  google.protobuf.Timestamp updated_at = 7;
}

message ListProductsRequest {
  // 可选类别过滤
  string category = 1;

  // 最小价格过滤(单位:分)
  optional int64 min_price_cents = 2;

  // 返回的最大项目数
  int32 page_size = 3;

  // 来自先前响应的页面令牌
  string page_token = 4;
}

message ListProductsResponse {
  repeated Product products = 1;
  string next_page_token = 2;
  int32 total_count = 3;
}

message CreateProductRequest {
  string name = 1;
  string description = 2;
  int64 price_cents = 3;
  string category = 4;
}

message CreateProductResponse {
  Product product = 1;
}

示例4:错误响应设计(REST)

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "请求验证失败",
    "details": [
      {
        "field": "email",
        "code": "INVALID_FORMAT",
        "message": "邮箱必须是有效的邮箱地址"
      },
      {
        "field": "age",
        "code": "OUT_OF_RANGE",
        "message": "年龄必须在18到120岁之间"
      }
    ],
    "request_id": "req_abc123xyz",
    "documentation_url": "https://api.example.com/docs/errors#VALIDATION_ERROR"
  }
}

示例5:使用头部进行API版本控制

# 带API版本头部的请求
GET /users/123 HTTP/1.1
Host: api.example.com
Accept: application/vnd.api.v2+json
Authorization: Bearer eyJ...

# 响应包含弃用警告
HTTP/1.1 200 OK
Content-Type: application/vnd.api.v2+json
Sunset: Sat, 31 Dec 2026 23:59:59 GMT
Deprecation: true
Link: <https://api.example.com/v3/users/123>; rel="successor-version"

{
  "id": "123",
  "email": "user@example.com",
  "name": "John Doe"
}