openapi-contract

v2026.09.24

OpenAPI contract validation between frontend and backend. Covers type sync, endpoint validation, and contract-first development. USE WHEN: user asks about "OpenAPI validation", "API contract", "swagger sync", "frontend backend types", "API mismatch", "contract testing" DO NOT USE FOR: GraphQL - use `graphql-contract` skill, authentication - use `auth-flow-validation` skill

GitHub
安装命令
npx skhub add claude-dev-suite/openapi-contract
Markdown
SKILL.md

OpenAPI Contract Validation - Quick Reference

When NOT to Use This Skill

  • GraphQL APIs - Use graphql-contract skill
  • Authentication flows - Use auth-flow-validation skill
  • API versioning strategy - Use api-versioning skill
  • Type generation setup - Use type-generation skill

Deep Knowledge: Use mcp__api-explorer__get_api_endpoint_details for specific endpoint validation.

Contract Validation Overview

┌─────────────────────────────────────────────────────────────┐
│                    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                             │
└─────────────────────────────────────────────────────────────┘

Common Discrepancy Types

1. Path Mismatch

# OpenAPI Spec
paths:
  /users/{userId}:     # Backend path
    get: ...

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

Detection:

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

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

Fix: Update frontend to use correct path or configure base URL.

2. Type Mismatch

# OpenAPI Spec
components:
  schemas:
    User:
      properties:
        age:
          type: string    # Backend uses string

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

Detection:

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

// Should be
interface CreateUserDto {
  age: string;  // Match OpenAPI spec
}

3. Required Field Missing

# 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. Response Structure Mismatch

# 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;

Validation Checklist

Per-Endpoint Validation

CheckFrontendBackend (OpenAPI)Status
Path/api/users/usersMISMATCH
MethodPOSTPOSTOK
Content-Typeapplication/jsonapplication/jsonOK
Request Bodymatches schemaCreateUserRequestCHECK
Response Typematches schemaUserCHECK
Status Codeshandles 400, 401200, 400, 401, 500PARTIAL

Request Body Validation

// 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?
}

Response Handling Validation

// 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;
}

Contract-First Development

1. Define OpenAPI Spec First

# 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. Generate Types for Both Ends

# 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. Implement Against Generated Types

// 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 Usage

Efficient Validation Queries

// 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
});

Avoid Token Waste

// 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"
});

Automated Contract Testing

Prism (Mock Server)

# 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 Fuzzing)

# 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 (Contract Testing)

# Test implementation matches spec
dredd openapi.yaml http://localhost:8080

CI/CD Integration

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

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
Manual type syncDrift over timeGenerate from spec
Ignoring OpenAPI specNo source of truthContract-first development
Hardcoded URLsEnvironment issuesConfigure base URL
No validation in CIBreaks discovered lateAutomated contract tests
Any types for APINo type safetyGenerate proper types

Quick Troubleshooting

IssueLikely CauseSolution
Types out of syncManual updatesRegenerate from spec
404 errorsPath mismatchCheck OpenAPI paths
400 Bad RequestMissing required fieldValidate against schema
Unexpected responseResponse structure changedUpdate frontend types
CORS errorsBackend configCheck allowed origins

Related Skills

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/integration-validation/openapi-contract

默认分支

main

最新提交

9496306

Tree SHA

fe4e2f1