Lesson 2: API Contracts
What Are API Contracts?
An API contract defines the expected interface between services—what they exchange, in what format, and what errors can occur. Contracts enable:
- Consumer-driven contracts: API consumers define what they need
- Contract testing: Automatically verify implementations match
- Documentation: Self-documenting APIs
- Versioning: Manage API evolution safely
Why Contracts in Architecture?
Contracts are the boundaries between components. Good contracts:
- Make dependencies explicit
- Enable independent evolution
- Prevent breaking changes
- Enable contract testing in CI/CD
Defining Contracts in Sruja
// partial
import { * } from 'sruja.ai/stdlib'
contract "Payment Contract" {
description "Contract for payment processing service"
input {
amount integer "Payment amount in cents"
currency string "ISO 4217 currency code"
customer_id string "Customer identifier"
}
output {
transaction_id string "Unique transaction identifier"
status string "Payment status"
}
error {
"400" "Invalid request parameters"
"402" "Payment declined"
"500" "Internal server error"
}
constraint "Response time must be < 50ms"
}
Contract Fields
Each field in input/output has a name, type, and description:
input {
field_name type "Description of the field"
}
Supported types: string, integer, boolean, array, object
Contract Integrity Validation
# Validate all contracts
sruja validate --contracts
# Check specific contract
sruja validate payment.sruja
Validation checks:
- ✅ All fields have valid types
- ✅ Error codes are properly formatted
- ✅ Constraints are well-defined
- ✅ Contracts are used by existing elements
Contracts on Containers
Apply contracts to containers to define their interfaces:
// partial
PaymentService = container "Payment Service" {
technology "Node.js"
description "Handles payment processing"
contract "Process Payment" {
input {
amount integer "Amount in cents"
currency string "Currency code"
}
output {
transaction_id string "Transaction ID"
status string "Payment status"
}
error {
"400" "Invalid request"
"402" "Payment declined"
}
}
}
OrderService = container "Order Service" {
technology "Go"
description "Manages orders"
}
// OrderService uses PaymentService's contract
OrderService -> PaymentService "Processes payment via contract"
Using Contracts for Testing
Generate test cases from contracts:
# Generate mock implementations
sruja contract mock "Payment Contract" --output ./tests/mocks/
# Generate test cases
sruja contract test "Payment Contract" --framework jest
Module Complete!
You've completed Behavioral Modeling. You now understand:
- ✅ State machines and state transitions
- ✅ API contracts with input/output/error definitions
- ✅ Scenario writing and validation
- ✅ CI/CD integration for behavioral testing
Next steps: Module 3 covers Intent-Driven Development.