16 KiB
description, shortcut, category, difficulty, estimated_time, version
| description | shortcut | category | difficulty | estimated_time | version |
|---|---|---|---|---|---|
| Generate comprehensive API contracts for consumer-driven contract testing | contract | api | intermediate | 3-5 minutes | 2.0.0 |
Generate API Contract
Creates comprehensive API contracts for consumer-driven contract testing, enabling safe evolution of microservices by validating interactions between service consumers and providers. Supports Pact, Spring Cloud Contract, and OpenAPI specifications with automated verification and CI/CD integration.
When to Use
Use this command when:
- Building microservices that need to evolve independently
- Implementing consumer-driven contract testing (CDCT)
- Preventing breaking changes between API versions
- Setting up automated compatibility testing in CI/CD
- Documenting API expectations between teams
- Migrating from monolithic to microservice architecture
- Establishing service boundaries and contracts
Do NOT use this command for:
- Internal function testing (use unit tests instead)
- UI testing (use end-to-end tests)
- Performance testing (use load testing tools)
- Security testing (use security scanning tools)
Prerequisites
Before running this command, ensure:
- API endpoints are defined (at least conceptually)
- Consumer and provider services are identified
- Testing framework is chosen (Pact, Spring Cloud Contract, etc.)
- API documentation exists or requirements are clear
- Version control is set up for contract storage
Process
Step 1: Analyze API Requirements
The command examines your API specifications to generate appropriate contracts:
- Identifies HTTP methods and endpoints
- Extracts request/response schemas
- Determines required headers and parameters
- Captures validation rules and constraints
- Notes authentication requirements
Step 2: Generate Contract Definitions
Based on the analysis, creates contract files that include:
- Consumer expectations (what the consumer needs)
- Provider capabilities (what the provider offers)
- Interaction definitions (request/response pairs)
- State management (preconditions for tests)
- Metadata for versioning and identification
Step 3: Create Verification Tests
Generates test code to verify contracts:
- Consumer-side tests to ensure correct API usage
- Provider-side tests to verify implementation
- Mock server configurations for isolated testing
- Integration points for CI/CD pipelines
- Breaking change detection logic
Step 4: Configure Contract Management
Sets up infrastructure for contract lifecycle:
- Contract versioning strategies
- Pact Broker or contract repository configuration
- CI/CD pipeline integration scripts
- Webhook configurations for automated testing
- Documentation generation from contracts
Output Format
The command generates multiple files based on your chosen framework:
api-contracts/
├── consumers/
│ ├── [consumer-name]/
│ │ ├── pacts/
│ │ │ └── [consumer]-[provider].json
│ │ └── tests/
│ │ └── contract.test.js
├── providers/
│ ├── [provider-name]/
│ │ ├── contracts/
│ │ │ └── [provider]-contract.groovy
│ │ └── tests/
│ │ └── contract-verification.test.js
├── shared/
│ ├── schemas/
│ │ └── api-schema.json
│ └── states/
│ └── provider-states.js
└── docs/
└── contract-documentation.md
Output Files Explained:
pacts/: Pact contract files in JSON formatcontracts/: Spring Cloud Contract definitions in Groovy/YAMLtests/: Generated test files for contract verificationschemas/: Shared schema definitions (JSON Schema, OpenAPI)states/: Provider state setup for test scenariosdocs/: Human-readable contract documentation
Examples
Example 1: REST API User Service Contract
Scenario: Generate contract for a user service with CRUD operations
User Input:
/generate-contract --service user-api --consumer mobile-app --framework pact
Generated Pact Contract:
{
"consumer": {
"name": "mobile-app"
},
"provider": {
"name": "user-api"
},
"interactions": [
{
"description": "a request to get a user",
"providerState": "user with ID 123 exists",
"request": {
"method": "GET",
"path": "/api/users/123",
"headers": {
"Accept": "application/json",
"Authorization": "Bearer [token]"
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
"id": "123",
"email": "[email protected]",
"name": "John Doe",
"createdAt": "2025-01-15T10:00:00Z"
},
"matchingRules": {
"$.body.email": {
"match": "type"
},
"$.body.createdAt": {
"match": "regex",
"regex": "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z"
}
}
}
},
{
"description": "a request to create a user",
"providerState": "no user exists",
"request": {
"method": "POST",
"path": "/api/users",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer [token]"
},
"body": {
"email": "[email protected]",
"name": "Jane Smith",
"password": "SecurePass123!"
}
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json",
"Location": "/api/users/124"
},
"body": {
"id": "124",
"email": "[email protected]",
"name": "Jane Smith",
"createdAt": "2025-01-15T11:00:00Z"
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "2.0.0"
}
}
}
Generated Consumer Test:
// consumer-tests/user-api.test.js
const { Pact } = require('@pact-foundation/pact');
const { getUserById, createUser } = require('../src/api-client');
describe('User API Consumer Tests', () => {
const provider = new Pact({
consumer: 'mobile-app',
provider: 'user-api',
port: 8080,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'pacts'),
logLevel: 'warn'
});
beforeAll(() => provider.setup());
afterEach(() => provider.verify());
afterAll(() => provider.finalize());
describe('GET /api/users/:id', () => {
it('should return a user when user exists', async () => {
// Arrange
await provider.addInteraction({
state: 'user with ID 123 exists',
uponReceiving: 'a request to get a user',
withRequest: {
method: 'GET',
path: '/api/users/123',
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer valid-token'
}
},
willRespondWith: {
status: 200,
headers: {
'Content-Type': 'application/json'
},
body: {
id: '123',
email: '[email protected]',
name: 'John Doe',
createdAt: '2025-01-15T10:00:00Z'
}
}
});
// Act
const user = await getUserById('123', 'valid-token');
// Assert
expect(user.id).toBe('123');
expect(user.email).toBe('[email protected]');
});
});
});
Example 2: Spring Cloud Contract for Payment Service
Scenario: Generate contract for payment processing service
User Input:
/contract --service payment-service --consumer checkout-app --framework spring
Generated Spring Cloud Contract (Groovy):
// contracts/payment/process-payment.groovy
package contracts.payment
import org.springframework.cloud.contract.spec.Contract
Contract.make {
description "Process a payment transaction"
label "process_payment"
request {
method POST()
url "/api/payments"
headers {
contentType(applicationJson())
header("Authorization", "Bearer ${anyNonEmptyString()}")
}
body([
amount: 99.99,
currency: "USD",
customerId: anyUuid(),
paymentMethod: [
type: "CARD",
cardNumber: regex('[0-9]{16}'),
expiryMonth: regex('(0[1-9]|1[0-2])'),
expiryYear: regex('20[2-9][0-9]'),
cvv: regex('[0-9]{3}')
],
orderId: anyUuid()
])
}
response {
status 200
headers {
contentType(applicationJson())
}
body([
transactionId: anyUuid(),
status: "APPROVED",
amount: 99.99,
currency: "USD",
processedAt: anyIso8601DateTime(),
authorizationCode: regex('[A-Z0-9]{6}')
])
}
}
Generated Provider Verification Test:
// PaymentContractVerificationTest.java
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@AutoConfigureWebTestClient
public class PaymentContractVerificationTest {
@LocalServerPort
private int port;
@MockBean
private PaymentService paymentService;
@TestTarget
public final Target target = new SpringBootHttpTarget();
@Before
public void setup() {
RestAssuredMockMvc.webAppContextSetup(context);
}
@State("payment service is available")
public void paymentServiceAvailable() {
// Setup mock responses
PaymentResponse response = PaymentResponse.builder()
.transactionId(UUID.randomUUID().toString())
.status("APPROVED")
.amount(99.99)
.currency("USD")
.processedAt(Instant.now())
.authorizationCode("ABC123")
.build();
when(paymentService.processPayment(any(PaymentRequest.class)))
.thenReturn(response);
}
}
Example 3: OpenAPI Contract with Validation
Scenario: Generate OpenAPI contract with request/response validation
User Input:
/generate-contract --service product-catalog --format openapi --with-validation
Generated OpenAPI Specification:
openapi: 3.0.3
info:
title: Product Catalog API Contract
version: 1.0.0
description: Contract for product catalog service interactions
paths:
/api/products:
get:
operationId: getProducts
summary: List products with pagination
parameters:
- name: page
in: query
required: false
schema:
type: integer
minimum: 1
default: 1
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ProductList'
examples:
success:
value:
products:
- id: "prod-123"
name: "Widget Pro"
price: 29.99
stock: 150
pagination:
page: 1
limit: 20
total: 45
components:
schemas:
ProductList:
type: object
required:
- products
- pagination
properties:
products:
type: array
items:
$ref: '#/components/schemas/Product'
pagination:
$ref: '#/components/schemas/Pagination'
Product:
type: object
required:
- id
- name
- price
- stock
properties:
id:
type: string
pattern: '^prod-[a-z0-9]+$'
name:
type: string
minLength: 1
maxLength: 200
price:
type: number
minimum: 0
multipleOf: 0.01
stock:
type: integer
minimum: 0
Error Handling
Error: Missing API Documentation
Symptoms: No OpenAPI spec or API documentation available Cause: API not yet documented or in early development Solution:
The command will guide you through interactive API definition:
- Define endpoints and methods
- Specify request/response formats
- Add validation rules
- Generate initial documentation
Prevention: Document APIs as part of development process
Error: Incompatible Contract Versions
Symptoms: Consumer and provider contracts don't match Cause: Services evolved independently without coordination Solution:
Contract Version Migration:
1. Identify breaking changes
2. Create compatibility layer
3. Version contracts appropriately
4. Implement gradual migration
Error: Contract Verification Failure
Symptoms: Provider tests fail against consumer contracts Cause: Implementation doesn't match contract expectations Solution:
Debug Contract Mismatches:
1. Review failed interaction details
2. Check request/response differences
3. Update implementation or contract
4. Re-run verification tests
Configuration Options
The contract generation can be customized with:
Option: --framework
- Purpose: Choose contract testing framework
- Values:
pact,spring,openapi,postman - Default:
pact - Example:
/contract --framework spring
Option: --strict
- Purpose: Enable strict validation rules
- Default: false
- Example:
/contract --strict
Option: --version
- Purpose: Specify contract version
- Default: Auto-incremented
- Example:
/contract --version 2.0.0
Best Practices
✅ DO:
- Version your contracts alongside API versions
- Run contract tests in CI/CD pipeline
- Use contract broker for centralized management
- Document breaking changes clearly
- Test both happy path and error scenarios
❌ DON'T:
- Modify generated contracts manually without updating source
- Skip contract verification before deployment
- Use contracts as replacement for all testing
- Ignore contract test failures
💡 TIPS:
- Start with consumer-driven contracts for better API design
- Use semantic versioning for contract versions
- Implement backwards compatibility when possible
- Share contracts between teams early in development
Related Commands
/api-versioning-manager- Manage API versions and migrations/api-documentation-generator- Generate comprehensive API docs/api-mock-server- Create mock servers from contracts/api-testing-suite- Generate integration test suites
Performance Considerations
- Generation time: 2-5 seconds for typical API
- Contract size: Usually <100KB per service pair
- Test execution: Milliseconds for contract tests
- Scaling: Supports hundreds of service interactions
Security Notes
⚠️ Security Considerations:
- Never include real credentials in contracts
- Use token placeholders for authentication
- Sanitize sensitive data in examples
- Store contracts in version control securely
- Implement contract access controls in broker
Troubleshooting
Issue: Contracts not being published
Solution: Check broker credentials and network connectivity
Issue: Mock server not starting
Solution: Verify port availability and permissions
Issue: Contract tests timing out
Solution: Increase timeout values for slow services
Getting Help
- Pact documentation: https://docs.pact.io
- Spring Cloud Contract: https://spring.io/projects/spring-cloud-contract
- OpenAPI specification: https://swagger.io/specification/
Version History
- v2.0.0 - Complete rewrite with multi-framework support
- v1.0.0 - Initial Pact-only implementation
Last updated: 2025-10-11 Quality score: 9+/10 Tested with: Pact v10, Spring Cloud Contract v4, OpenAPI v3.0.3