mcpField
O
openapi-contract

openapi-contract

github.com/claude-dev-suite测试与质量4638 次安装2 天前更新
代码仓库

关于 openapi-contract

用于检查前后端 API 调用是否符合 OpenAPI 合约的参考技能,帮助开发者发现端点、类型、请求和响应不一致,并介绍契约优先开发与自动化测试。

主要功能

  1. 01端点与方法检查
  2. 02请求和响应模式验证
  3. 03常见合约差异诊断
  4. 04契约优先开发指南
  5. 05自动化测试与 CI 示例

适用场景

  1. 01查找与 API 规范不符的前端路径
  2. 02检查请求字段和响应类型
  3. 03在 CI 流程中添加合约测试

MCP 相关

该技能介绍使用 api-explorer MCP 工具搜索 API 路径并获取特定端点详情。它建议进行针对性端点查询,而不是加载完整模式。

安装

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

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill openapi-contract

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

详细介绍

OpenAPI 契约验证 - 快速参考

不适用此技能的情况

  • GraphQL API - 使用 graphql-contract 技能
  • 身份验证流程 - 使用 auth-flow-validation 技能
  • API 版本管理策略 - 使用 api-versioning 技能
  • 类型生成设置 - 使用 type-generation 技能

深入了解:使用 mcp__api-explorer__get_api_endpoint_details 验证特定端点。

契约验证概述

┌─────────────────────────────────────────────────────────────┐
│                    CONTRACT VALIDATION                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   Frontend Code          OpenAPI Spec           Backend      │
│   ┌──────────────┐      ┌────────────┐     ┌──────────────┐ │
│   │ fetch('/api/ │ ←──→ │ paths:     │ ←──→│ @Controller  │ │
│   │   users')    │      │  /users:   │     │ @GetMapping  │ │
│   │              │      │    get:    │     │              │ │
│   │ type User {  │ ←──→ │ schemas:   │ ←──→│ class UserDto│ │
│   │   id: number │      │  User:     │     │   Long id    │ │
│   │ }            │      │    id:int  │     │              │ │
│   └──────────────┘      └────────────┘     └──────────────┘ │
│                                                              │
│        MUST MATCH          SOURCE OF           MUST MATCH   │
│                            TRUTH                             │
└─────────────────────────────────────────────────────────────┘

常见差异类型

1. 路径不匹配
# OpenAPI Spec
paths:
  /users/{userId}:     # Backend path
    get: ...

# Frontend Code
fetch('/api/users/${id}')  # Frontend uses different path!

检测:

# Find API calls in frontend
grep -r "fetch\|axios\|http\." src/

# Compare with OpenAPI paths
# Use api-explorer to list paths

修复: 更新前端以使用正确的路径,或配置基础 URL。

2. 类型不匹配
# OpenAPI Spec
components:
  schemas:
    User:
      properties:
        age:
          type: string    # Backend uses string

# Frontend Code
interface User {
  age: number;            # Frontend expects number!
}

检测:

// Frontend type
interface CreateUserDto {
  age: number;  // MISMATCH
}

// Should be
interface CreateUserDto {
  age: string;  // Match OpenAPI spec
}
3. 缺少必填字段
# OpenAPI Spec
components:
  schemas:
    CreateUserRequest:
      required:
        - email
        - name
        - role          # Required!
      properties:
        email: { type: string }
        name: { type: string }
        role: { type: string }

# Frontend Code
const payload = {
  email: user.email,
  name: user.name,
  // role is missing!  <-- Will fail validation
};
4. 响应结构不匹配
# OpenAPI Spec - Paginated response
paths:
  /users:
    get:
      responses:
        200:
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  meta:
                    $ref: '#/components/schemas/PaginationMeta'

# Frontend Code - Expects array directly
const users: User[] = await response.json();  // WRONG!
// Should be
const { data, meta } = await response.json();
const users: User[] = data;

验证清单

按端点验证
检查项前端后端(OpenAPI)状态
路径/api/users/usersMISMATCH
方法POSTPOSTOK
Content-Typeapplication/jsonapplication/jsonOK
请求正文与架构匹配CreateUserRequestCHECK
响应类型与架构匹配UserCHECK
状态码处理 400、401200、400、401、500PARTIAL
请求正文验证
// OpenAPI Schema
interface CreateUserRequest {
  email: string;      // required
  name: string;       // required
  age?: number;       // optional
  role: UserRole;     // required, enum
}

// Validate frontend matches
interface FrontendPayload {
  email: string;      // OK - required
  name: string;       // OK - required
  age?: number;       // OK - optional
  role: 'admin' | 'user';  // CHECK - enum values match?
}
响应处理验证
// OpenAPI Response
interface ApiResponse<T> {
  data: T;
  meta?: {
    page: number;
    total: number;
  };
  error?: {
    code: string;
    message: string;
  };
}

// Frontend should handle all cases
async function fetchUsers(): Promise<User[]> {
  const response = await fetch('/api/users');

  if (!response.ok) {
    const error = await response.json();
    throw new ApiError(error.error.code, error.error.message);
  }

  const result: ApiResponse<User[]> = await response.json();
  return result.data;
}

契约优先开发

1. 先定义 OpenAPI 规范
# openapi.yaml
openapi: 3.0.3
info:
  title: User API
  version: 1.0.0

paths:
  /users:
    post:
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'

components:
  schemas:
    CreateUserRequest:
      type: object
      required: [email, name]
      properties:
        email:
          type: string
          format: email
        name:
          type: string
          minLength: 2
          maxLength: 100

    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
        name:
          type: string
        createdAt:
          type: string
          format: date-time
2. 为两端生成类型
# Frontend (TypeScript)
npx openapi-typescript openapi.yaml -o src/api/types.ts

# Backend (Java/Spring)
npx @openapitools/openapi-generator-cli generate \
  -i openapi.yaml \
  -g spring \
  -o generated/
3. 根据生成的类型进行实现
// Frontend - uses generated types
import type { CreateUserRequest, User } from './api/types';

async function createUser(data: CreateUserRequest): Promise<User> {
  const response = await fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  });
  return response.json();
}
// Backend - uses generated DTOs
@PostMapping("/users")
public ResponseEntity<User> createUser(
    @Valid @RequestBody CreateUserRequest request) {
    // Implementation uses generated types
}

MCP api-explorer 用法

高效验证查询
// 1. Search for endpoint
await mcp__api_explorer__search_api({
  query: "users",
  searchIn: ["paths"],
  limit: 10
});

// 2. Get specific endpoint details
await mcp__api_explorer__get_api_endpoint_details({
  path: "/users",
  method: "POST"
});

// 3. Get request/response schemas
await mcp__api_explorer__get_api_models({
  model: "CreateUserRequest",
  compact: true
});
避免浪费 Token
// DON'T - Loads entire spec
await mcp__api_explorer__get_api_schema({ format: "full" });

// DO - Query specific endpoints
await mcp__api_explorer__get_api_endpoint_details({
  path: "/users/{id}",
  method: "GET"
});

自动化契约测试

Prism(模拟服务)
# Start mock server from OpenAPI spec
npx @stoplight/prism-cli mock openapi.yaml

# Run frontend tests against mock
npm test -- --api-url=http://localhost:4010
Schemathesis(API 模糊测试)
# Test backend against OpenAPI spec
schemathesis run openapi.yaml --base-url=http://localhost:8080

# Validate all endpoints
schemathesis run openapi.yaml \
  --checks all \
  --validate-schema
Dredd(契约测试)
# Test implementation matches spec
dredd openapi.yaml http://localhost:8080

CI/CD 集成

GitHub Actions
name: Contract Validation
on: [push, pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Validate OpenAPI spec
        run: npx @redocly/cli lint openapi.yaml

      - name: Generate types
        run: npx openapi-typescript openapi.yaml -o src/api/types.ts

      - name: Check types unchanged
        run: git diff --exit-code src/api/types.ts

      - name: Run contract tests
        run: npm run test:contract

反模式

反模式不良影响正确做法
手动同步类型随时间产生偏差从规范生成
忽略 OpenAPI 规范缺少唯一事实来源契约优先开发
硬编码 URL环境问题配置基础 URL
CI 中没有验证问题发现得太晚自动化契约测试
API 使用 Any 类型缺少类型安全生成正确的类型

快速故障排除

问题可能原因解决方案
类型不同步手动更新从规范重新生成
404 错误路径不匹配检查 OpenAPI 路径
400 Bad Request缺少必填字段根据架构验证
响应异常响应结构已更改更新前端类型
CORS 错误后端配置检查允许的来源

相关技能

评论

支持 Markdown