mcpField
B
backend-api

backend-api

github.com/iuliandita开发1149 次安装3 天前更新
代码仓库

关于 backend-api

面向设计和审查 HTTP API 的技能,适用于 Python 与 Node.js 服务开发者。覆盖 API 契约、认证边界、错误模型及框架实现,并提供逐步工作流与自检清单。

主要功能

  1. 01HTTP API 契约设计与审查
  2. 02分页、筛选与错误模型
  3. 03FastAPI、Express 和 NestJS 结构
  4. 04会话、OAuth 与令牌认证
  5. 05OpenAPI 文档和兼容性检查

适用场景

  1. 01规划新的 REST API
  2. 02审查现有 FastAPI 服务
  3. 03定义分页与错误响应规范
  4. 04设计客户端认证流程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/iuliandita/skills --skill backend-api

安装后在 Claude Code 中输入/backend-api确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
agent-hygiene.md
auth-and-session-patterns.md
graphql-grpc-patterns.md
http-api-patterns.md
output-contract.md

详细介绍

后端 API:HTTP 服务设计与实现

设计和审查随规模增长仍保持一致的 HTTP API。重点关注契约、认证边界、错误模型,以及 Python 和 Node.js 服务的框架结构。

目标版本(2026 年 10 月):

  • FastAPI 0.142.2
  • Express 5.2.1(发布于 2025-12-01)
  • NestJS 12.1.2(主版本发布;升级前请查看迁移说明;12.0.2+ 修复了高危 微服务 和 Fastify 中间件绕过安全公告)
  • OpenAPI Specification 3.2.1(发布于 2026-09-10)
  • HTTP 语义:RFC 9110(2022 年 6 月)
  • HTTP API 问题详情:RFC 9457(2023 年 7 月)
  • OAuth 2.0 安全最佳实践:RFC 9700(2025 年 1 月)

安全检查(2026-10-28):使用 Multer <2.3.0 的 Express/NestJS 上传技术栈会受到高危多部分请求拒绝服务漏洞的影响:CVE-2026-82333。 请将 Multer 升级到 2.5.0+(2.5.0 修复了请求拆除后仍有待处理异步 fileFilter 导致的高危 DoS 漏洞:CVE-2026-113872;2.4.0 修复了中危的中止上传导致磁盘耗尽漏洞:CVE-2026-88932),并根据应用需求限制 limits.fieldArrayIndexLimit;只检查顶层框架版本会漏掉存在漏洞的中间件。

此技能涵盖以下方面:

  • 契约设计 - 资源、方法、状态码、架构、版本控制
  • API 易用性 - 分页、筛选、排序、幂等性、错误格式
  • 框架结构 - FastAPI 依赖项、Express 中间件、NestJS 模块和守卫
  • 身份验证 - 会话、Bearer 令牌、OAuth/OIDC、BFF 和令牌中介
  • 审查 - 不稳定的契约、DTO 泄漏、身份验证混淆和 HTTP 误用
  • 有界协议模式 - 在 GraphQL 或 gRPC 已纳入范围时,提供 GraphQL 架构/解析器和 gRPC 契约、截止时间、重试及流式传输防护

适用场景

  • 设计新的 REST 或 HTTP API
  • 审查现有的 FastAPI、Express 或 NestJS 服务
  • 编写或修复 OpenAPI 规范和生成的文档
  • 选择状态码、错误格式、分页、筛选或版本控制策略
  • 为浏览器、移动设备、机器间或第三方客户端设计身份验证流程
  • 重构难以理解的路由或控制器结构
  • 规划向后兼容的 API 演进
  • 定义写入端点的幂等性和重试行为

不适用场景

  • 独立的 GraphQL 联邦架构或协议级 gRPC 平台管理——请先缩小请求范围;此技能涵盖服务契约模式,不是框架目录
  • 数据库架构、索引、复制或查询调优——使用 databases
  • API 边界之外的一般错误查找、竞态条件排查或正确性审查——使用 code-review
  • 针对身份验证绕过、注入、密钥或 OWASP 问题的安全审计——使用 security-audit
  • 编写或调试自动化测试——使用 testing
  • 部署、容器、网关、入口或集群配置——使用 docker、kubernetes 或 networking
  • API 交付的 CI/CD 流水线设计——使用 ci-cd
  • MCP 专用 HTTP 服务和工具处理程序——使用 mcp

AI 自检

在返回 API 代码、路由设计或 OpenAPI 输出之前,请确认:

  • 资源名称使用名词,URL 结构稳定(/users/{userId}/sessions,而非 /doUserSessionThing)
  • 方法语义遵循 RFC 9110——不能使用会产生变更的“GET”,也不能把 PATCH 当作含糊不清的万能方法
  • 401 与 403 使用正确:前者表示未通过身份验证,后者表示已通过身份验证但无权访问
  • 有意且一致地处理所有权隐藏行为:确定范围外资源何时返回 404,何时返回 403
  • 错误响应采用统一格式,优先使用 RFC 9457 问题详情格式
  • 请求和响应 DTO 明确,并与 ORM 或数据库模型分开
  • 即使客户端或 SDK 也会执行验证,仍须在服务端验证输入
  • 对于大型集合或变化频繁的集合,不要盲目使用偏移分页;此类场景下游标分页通常更安全
  • 可能会重试的写入端点(POST /payments、webhook 接收器、订单创建)定义幂等行为
  • OpenAPI 文档与实际处理程序行为、示例、状态码和身份验证要求一致
  • 第一方浏览器应用默认不在浏览器存储中保存长期有效的 bearer token
  • 基于 Cookie 的浏览器身份验证应考虑 Cookie 作用范围和 CSRF 行为,而非假设 Cookie 天然安全
  • OAuth 指引符合当前规范:使用授权码 + PKCE,不使用隐式授权流程,也不使用资源所有者密码凭据
  • 明确敏感项的默认设置:Cookie 标志、令牌 TTL、作用域边界和速率限制不能含糊带过
  • 已检查框架版本:FastAPI、Express、NestJS 和 OpenAPI 示例与当前 API 及迁移说明一致
  • 已检查契约兼容性:除非明确升级版本,否则响应码、分页、错误和身份验证行为应保持与现有客户端兼容
  • 将处理程序主体中的注入标记为契约缺陷:如果在路由处理程序中发现注入(SQL、命令、标头、路径遍历),应将其标记为契约层缺少验证边界的缺陷,并建议在该层修复;如果此类模式普遍存在,则转交给 security-audit 进行全面注入审计
  • 已应用跨领域 Agent 卫生规范——参见 references/agent-hygiene.md

性能

  • 在数据存储层进行分页和筛选;切勿为了在处理程序中切片而加载整个集合。
  • 在框架、代理和客户端层设置超时和请求体大小限制。
  • 在优化内部实现之前,测量变更端点的 p95/p99 延迟和错误率。

最佳实践

  • 在处理程序中使用明确的身份验证作用域和租户检查,而不只是依赖路由分组或 UI 状态。

工作流

**构建与审查:**审查现有服务时,仍应遵循相同步骤。确定 API 边界,审计契约,追踪身份验证,然后将实现与已发布的行为进行比较,而不是直接跳到处理程序代码。

顺序很重要:契约先于处理程序。复制并跟踪以下步骤:

  • 步骤 1:明确边界、调用方、稳定性承诺和项目惯例
  • 步骤 2:框架模式与代码库一致
  • 步骤 3:定义契约(资源、方法、架构、错误、分页、版本控制)
  • 步骤 4:根据客户端类型选择身份验证模型
  • 步骤 5:按照契约实现框架层接口
  • 步骤 6:验证行为和文档(若未通过,返回步骤 3 或步骤 5)
步骤 1:确定边界

在选择框架模式之前,先明确 API:

  • 谁来调用? 浏览器应用、移动应用、第三方集成方、内部服务、Webhook 发送方
  • 这是什么类型的 API? 公共 API、私有应用后端、内部服务、管理 API
  • 这是从零开始的任务还是评审? 新设计、增量变更、迁移或 Bug 修复
  • 稳定性承诺是什么? 仅供内部使用、带版本的公共 API,还是“尽力而为”
  • 现有的身份验证模型是什么? Session Cookie、JWT Bearer、API 密钥、OAuth/OIDC,还是尚未设置
  • 现有的项目规范是什么? 错误格式、分页形式、版本方案、身份验证边界、DTO 命名

如果用户要求“只添加一个端点”,请先检查周边服务。许多糟糕的 API 工作,都是因为某个路由采用了与服务其余部分不同的错误模型、身份验证规则、分页形式或 DTO 风格。

步骤 2:选择框架模式

选择符合代码库和团队约束的框架。不要为了赶时髦而更换框架。

框架最适用场景注意事项
FastAPI使用类型化请求/响应模型且需要完善 OpenAPI 输出的 Python 服务直接暴露 ORM 模型、混淆异步用法、将业务逻辑塞进路由函数
Express精简的 Node.js 服务、自定义中间件栈、现有的成熟代码库没有内置结构、验证逻辑散落在各个中间件中、错误处理不一致
NestJS适合采用模块、守卫、管道、拦截器和依赖注入的大型 TypeScript 服务过度抽象、装饰器过多导致间接层次繁杂、用过多层封装简单流程
步骤 3:先设计契约

编写处理器之前,先定义 API 契约:

对于现有服务的变更,除非任务明确包含迁移,否则应遵循当前的 URL、错误、分页和身份验证规范。

  1. 选择资源结构和 URI
  2. 选择方法和状态码
  3. 定义请求和响应架构
  4. 定义错误形式
  5. 确定分页、筛选、排序和版本规则
  6. 最后再接入框架实现

对于 GraphQL 或 gRPC 边界,在适用的情况下默认遵循 REST/HTTP 规则,然后阅读 references/graphql-grpc-patterns.md,了解协议专属的契约、兼容性、截止时间、授权、分页和流式传输保护措施。

优先采用:

  • 基于名词的资源:/users/{userId}/sessions
  • 可预测的列表端点:GET /orders?cursor=...&limit=...&status=paid
  • 明确的写入语义:创建/命令使用 POST,完整替换使用 PUT,部分更新使用 PATCH,删除使用 DELETE
  • 为 POST /orders/{orderId}/cancel 等命令端点明确定义重试语义
  • 整个服务采用统一的规范错误模型

阅读 references/http-api-patterns.md,了解方法语义、分页、幂等性和版本规则。

步骤 4:围绕客户端设计身份验证,而不是追逐 JWT 热潮

从客户端类型入手:

客户端默认选择原因
第一方浏览器应用会话 Cookie 或 BFF/令牌中介后端尽可能让令牌远离浏览器
原生/移动应用OAuth/OIDC 授权码 + PKCE当前公共客户端的标准方式
第三方集成方OAuth/OIDC;若 OAuth 过于复杂,则使用有作用域限制的 API 密钥明确的授权委托和撤销机制
内部服务间通信平台身份或短期服务凭据避免服务之间使用面向用户的身份验证流程

身份验证规则:

  • 对第一方 Web 应用,默认使用会话,除非有明确理由不这么做
  • 只有客户端确实需要持有令牌时,才使用 Bearer 令牌
  • 将 API 密钥视为机器凭据,而不是通用的身份验证捷径
  • 在 API 边界定义作用域或角色边界,不要在随意的处理程序中临时定义
  • 如果浏览器应用与第三方身份提供商通信,应遵循授权码 + PKCE 和当前的浏览器应用指南,而不是重新启用隐式授权流程模式

BFF 令牌中介(第一方浏览器应用调用外部 API):

Browser -> BFF (session cookie) -> BFF attaches Bearer token -> Upstream API

BFF 在服务端持有访问令牌;浏览器永远不会看到该令牌。

请阅读 references/auth-and-session-patterns.md,了解会话、Bearer 令牌、OAuth、BFF、刷新令牌和机器身份验证。

步骤 5:实现框架层

将契约转换为框架代码,但不要让框架决定契约。

FastAPI

  • 为请求和响应定义 Pydantic 模型
  • 使用依赖注入处理身份验证、数据库/会话获取和共享请求上下文
  • 注册异常处理程序,确保输出符合 RFC 9457 且保持一致
  • 保持路由处理程序精简;将业务规则移至服务或领域模块

Express

  • 在控制器逻辑执行前验证输入
  • 在中间件中附加身份验证信息和请求上下文
  • 使用统一的错误处理中间件路径
  • 控制器应作为传输适配器,而不是承载系统中所有规则的地方

NestJS

  • 使用 DTO 类定义传输边界
  • 在管道中进行验证,在守卫中处理身份验证
  • 使用异常过滤器或拦截器,统一响应和错误行为
  • 保持模块边界有意义;每个模糊概念都单独设一个模块并不等于架构
步骤 6:验证行为和文档

返回结果前,运行以下检查。如果有检查失败,请修复后返回步骤 3 处理契约缺陷,或返回步骤 5 处理实现缺陷,然后重新检查:

  • 将 OpenAPI 文档与实际路由进行对照
  • 验证各端点的身份验证要求
  • 检查所有非 2xx 响应,而不只是成功路径
  • 验证列表端点在空结果、部分结果和游标结束状态下的行为
  • 检查创建/支付/Webhook 路径的重试和重复提交
  • 检查命令端点(cancel、resend、approve)重复调用时的行为,不要让重试行为含糊不清
  • 将新端点与相邻端点进行对照,检查命名、DTO 结构、分页参数和错误一致性
  • 将后续测试工作交由 testing,将后续安全审查交由 security-audit

契约防护原则

版本控制
  • 优先采用增量式变更,而不是频繁变更版本
  • 只有在需要进行破坏性变更时才升级版本
  • 整个服务采用一种版本控制方案:对于公共 API,路径版本控制(/v1/...)是最清晰的默认选择
  • 不要在同一个 API 中混用路径版本控制、请求头版本控制和临时的 ?version= 查询参数
编写 OpenAPI

除非项目的工具链已证明能够端到端支持 3.2,否则请按 3.1 编写;参见 references/http-api-patterns.md 中的“OpenAPI 版本选择”。

错误模型
  • 优先使用 RFC 9457 问题详情,包含稳定的 type、title、status 和特定领域的扩展字段
  • 不要让验证、身份验证和业务规则各自返回不同的错误结构
  • 切勿向客户端泄露原始堆栈跟踪或 ORM 内部信息

最简 RFC 9457 问题详情响应:

{
  "type": "https://api.example.com/errors/insufficient-funds",
  "title": "Insufficient funds",
  "status": 422,
  "detail": "Account balance is $10.00; transfer requires $50.00."
}

状态码决策矩阵(选择最准确的状态码):

场景代码说明
JSON 格式错误、缺少必填字段、类型错误400客户端请求语法有误
输入格式正确,但不符合领域规则(余额不足、状态无效)422语义验证
没有凭据、令牌已过期401包含 WWW-Authenticate 标头
已通过身份验证,但未获授权403不要要求提供凭据
资源不存在,或资源存在但调用方不应知道404为每种资源选择一种策略并保持一致
写入与当前状态冲突(ETag 过期、唯一键重复)409问题详情应指出冲突
使用不同的请求正文重用了 Idempotency-Key422不是 409——密钥约定遭到违反
请求过多429包含 Retry-After
未处理的服务器错误500响应正文中绝不泄露堆栈跟踪

FastAPI 异常处理程序配置,确保统一返回 problem+json:

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError

app = FastAPI()

@app.exception_handler(RequestValidationError)
async def validation_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=400,
        media_type="application/problem+json",
        content={
            "type": "https://api.example.com/errors/validation",
            "title": "Invalid request",
            "status": 400,
            "errors": [
                {"location": [part for part in error.get("loc", ())
                              if isinstance(part, (str, int))],
                 "message": "Invalid value"}
                for error in exc.errors()
            ],
        },
    )
分页和筛选
  • 对于规模较小且稳定的后台列表,偏移分页即可
  • 面向用户或写入频繁的集合默认使用游标分页
  • 排序顺序必须稳定且有文档说明
  • 筛选器名称应反映资源字段或清晰的领域概念,而非内部 SQL 列名
幂等性和重试
  • 为客户端或网关可能重试的写入操作定义幂等性
  • 对类似支付或容易重放请求的操作使用显式幂等键
  • 存在异步工作流时,应区分“请求已接受”和“副作用已完成”

Express/NestJS 和 FastAPI 使用相同的事务协议;缓存的读取/写入/设置序列并非原子操作:

  1. 对操作进行身份验证和授权。限制标头长度,并将密钥限定到调用方或租户以及具体操作;对规范化后的请求进行哈希,生成指纹。
  2. 使用数据库唯一约束,以原子方式保留该作用域内的密钥。对于已有记录,若指纹不同则拒绝;若操作正在进行,则报告其状态,不要再次执行。仅当调用方和指纹都匹配时,才重放已完成且已授权的结果。
  3. 在同一事务中提交业务变更和已完成的响应记录。对于外部副作用,使用事务发件箱和服务提供方的幂等功能;数据库回滚无法撤销已发送的付款或消息。
  4. 在文档规定的重试窗口内保留结果。通过定义明确的状态转换来恢复中断的密钥保留操作,绝不要盲目地再次执行副作用。测试并发重复请求、两个调用方共享同一个密钥、请求正文不匹配,以及副作用与响应之间发生崩溃的情况。

游标分页响应封装:

{
  "data": [...],
  "next_cursor": "eyJpZCI6MTIzfQ",
  "has_more": true
}

在服务端解码游标(WHERE id > :cursor_id ORDER BY id LIMIT :limit)。切勿在游标中暴露原始数据库偏移量或行号。

不透明游标的编码/解码(FastAPI,使用 HMAC 签名以防止客户端篡改):

import base64, hmac, hashlib, json, os

SECRET = os.environ["CURSOR_SECRET"].encode()

def encode_cursor(payload: dict) -> str:
    body = base64.urlsafe_b64encode(json.dumps(payload, separators=(",", ":")).encode()).rstrip(b"=")
    sig = base64.urlsafe_b64encode(hmac.new(SECRET, body, hashlib.sha256).digest()[:8]).rstrip(b"=")
    return f"{body.decode()}.{sig.decode()}"

def decode_cursor(token: str) -> dict:
    body, sig = token.split(".", 1)
    expected = base64.urlsafe_b64encode(hmac.new(SECRET, body.encode(), hashlib.sha256).digest()[:8]).rstrip(b"=").decode()
    if not hmac.compare_digest(sig, expected):
        raise ValueError("invalid cursor")
    return json.loads(base64.urlsafe_b64decode(body + "=="))

客户端将 next_cursor 视为不透明值;其结构由服务端控制,并可在不破坏契约的情况下更改。

优雅关闭和滚动部署

滚动部署会在新实例启动时向旧实例发送 SIGTERM。请在 API 端处理,否则负载较高时可能出现 502 错误:

  • 捕获 SIGTERM,停止接受新连接,排空正在处理的请求,然后退出。FastAPI/Uvicorn:设置 --timeout-graceful-shutdown(默认未设置,因此 Uvicorn 会等待正在处理的请求完成且不设超时;生产环境中应设置有界值);Express 5:调用 server.close(),然后在排空窗口结束后调用 server.closeAllConnections();NestJS:调用 app.enableShutdownHooks(),并设置 onApplicationShutdown 处理程序
  • 确保应用的关闭窗口短于编排器的终止宽限期(Kubernetes 默认值为 30s)。app_shutdown < terminationGracePeriodSeconds,否则内核会杀死正在处理的工作
  • 将服务器 HTTP keep-alive 超时设置得长于上游后端连接的空闲超时(负载均衡器、入口)。如果 LB 保留的连接已被服务器关闭,下一个请求就会命中失效的套接字。常见的安全搭配:服务器 keep-alive 为 65s,位于空闲超时为 60s 的 LB 后方
  • 添加就绪探针,在排空开始前于收到 SIGTERM 时切换为失败状态。编排器会停止路由新流量,同时让正在处理的请求完成

不要强行采用的做法

  • 不要强行要求每个小型内部列表或后台管理表格都使用游标分页
  • 不要仅仅因为添加了新字段就切出 /v2
  • 如果范围限定的 API 密钥或平台身份更合适,就不要坚持要求每条内部自动化路径都使用 OAuth
  • 不要因为“JWT auth”听起来更现代,就让一方浏览器应用采用将 bearer token 存储在本地存储中的模式
  • 不要把简单的 Express 服务改造成带有多余层和装饰器的伪企业级架构

参考文件

  • references/http-api-patterns.md - 资源设计、方法语义、状态码、版本控制、分页、筛选、幂等性
  • references/auth-and-session-patterns.md - 会话与 bearer token、OAuth/OIDC、BFF、刷新令牌、机器客户端
  • references/graphql-grpc-patterns.md - 有界 GraphQL 和 gRPC 契约及兼容性模式

输出契约

完整契约请参见 references/output-contract.md。

  • 技能名称: BACKEND-API
  • 交付物类别: audits
  • 模式: 条件式。调用以分析、审查、审计或改进现有仓库内容时,遵循 references/output-contract.md 中的报告篇幅和证据规则,并将交付物写入 docs/local/audits/backend-api/<YYYY-MM-DD>-<slug>.md。调用以回答问题、讲解概念、构建新产物或生成内容时,可自由作答,不受该契约约束。
  • 严重性级别: P0 | P1 | P2 | P3 | info(参见共享契约;仅用于审计/审查模式)。

相关技能

  • databases - API 背后的架构设计、查询调优、迁移和持久化问题
  • code-review - 正确性缺陷、逻辑错误及与 API 无关的审查发现
  • security-audit - 认证绕过、OWASP 问题、机密,以及 API 设计完成后的安全审查
  • testing - 路由、集成、契约和端到端验证
  • docker - 将 API 服务容器化
  • kubernetes - 在集群上部署 API 服务
  • networking - 反向代理、TLS 终止、与 CORS 相关的网络边界及网关行为
  • ci-cd - API 服务的交付流水线
  • mcp - MCP 专用 HTTP 服务和认证模式
  • message-queues - 通过 202 Accepted 端点进行经由代理的异步交付、端点后方的队列,以及通过代理进行 webhook 扇出

规则

  1. 先定义契约,再编写处理程序。 在编写路由代码之前,先设计资源模型、架构、错误和身份验证边界。
  2. 不要让传输层泄漏持久化细节。 数据库表、ORM 实体和内部枚举都不是公共 API 契约。
  3. 保持框架结构简单明了。 控制器或路由保持精简,明确执行验证和身份验证,并集中处理错误。
  4. 向后兼容是一项特性。 新增字段成本低;破坏客户端兼容性代价高。
  5. 为真实的重试场景而设计。 假设客户端、代理和作业运行器会重放请求。
  6. 应用特定协议规则。 默认重点关注 REST;GraphQL 和 gRPC 需要遵循链接参考中的专属架构、兼容性、截止时间和流式传输检查。

评论

支持 Markdown