Agent skill

api-contract-testing

Verifies API contracts between services using consumer-driven contracts, schema validation, and tools like Pact. Use when testing microservices communication, preventing breaking changes, or validating OpenAPI specifications.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/api-contract-testing

SKILL.md

API Contract Testing

Verify that APIs honor their contracts between consumers and providers without requiring full integration tests.

Key Concepts

Term Definition
Consumer Service that calls an API
Provider Service that exposes an API
Contract Agreed request/response format
Pact Consumer-driven contract testing tool
Schema Structure definition (OpenAPI, JSON Schema)
Broker Central repository for contracts

Pact Consumer Test (TypeScript)

typescript
import { PactV3, MatchersV3 } from '@pact-foundation/pact';

const provider = new PactV3({
  consumer: 'OrderService',
  provider: 'UserService'
});

describe('User API Contract', () => {
  it('returns user by ID', async () => {
    await provider
      .given('user 123 exists')
      .uponReceiving('a request for user 123')
      .withRequest({ method: 'GET', path: '/users/123' })
      .willRespondWith({
        status: 200,
        body: MatchersV3.like({
          id: '123',
          name: MatchersV3.string('John'),
          email: MatchersV3.email('john@example.com')
        })
      })
      .executeTest(async (mockServer) => {
        const response = await fetch(`${mockServer.url}/users/123`);
        expect(response.status).toBe(200);
      });
  });

  it('returns 404 for non-existent user', async () => {
    await provider
      .given('user does not exist')
      .uponReceiving('a request for non-existent user')
      .withRequest({ method: 'GET', path: '/users/999' })
      .willRespondWith({
        status: 404,
        body: MatchersV3.like({
          error: { code: 'NOT_FOUND', message: MatchersV3.string() }
        })
      })
      .executeTest(async (mockServer) => {
        const response = await fetch(`${mockServer.url}/users/999`);
        expect(response.status).toBe(404);
      });
  });
});

Provider Verification

typescript
import { Verifier } from '@pact-foundation/pact';

new Verifier({
  provider: 'UserService',
  providerBaseUrl: 'http://localhost:3000',
  pactBrokerUrl: process.env.PACT_BROKER_URL,
  publishVerificationResult: true,
  providerVersion: process.env.GIT_SHA,
  stateHandlers: {
    'user 123 exists': async () => {
      await db.users.create({ id: '123', name: 'John' });
    },
    'user does not exist': async () => {
      await db.users.deleteAll();
    }
  }
}).verifyProvider();

OpenAPI Validation (Express)

javascript
const OpenApiValidator = require('express-openapi-validator');

app.use(OpenApiValidator.middleware({
  apiSpec: './openapi.yaml',
  validateRequests: true,
  validateResponses: true,
  validateSecurity: true
}));

Additional Implementations

Best Practices

Do:

  • Test from consumer perspective
  • Use matchers for flexible matching
  • Validate structure, not specific values
  • Version contracts explicitly
  • Test error responses
  • Run tests in CI pipeline
  • Test backward compatibility

Don't:

  • Test business logic in contracts
  • Hard-code specific values
  • Skip error scenarios
  • Ignore versioning
  • Deploy without verification

Tools

  • Pact - Multi-language consumer-driven contracts
  • Spring Cloud Contract - JVM ecosystem
  • OpenAPI/Swagger - Schema-first validation
  • Dredd - API blueprint testing
  • Spectral - OpenAPI linting

Didn't find tool you were looking for?

Be as detailed as possible for better results