Contract-Testing TM Forum Open APIs with Pact + Postman: Stop Breaking Your BSS
These articles are AI-generated summaries. Please check the original sources for full details.
Why Open APIs still break (even when you follow the spec)
TM Forum Open APIs like TMF620 Product Catalog and TMF622 Product Ordering are designed to give teams a common language for integration. However, version drift, the gap between provider updates and consumer adoption, consistently causes outages. These breaks can stem from seemingly minor changes – like omitting an optional field – that unexpectedly disrupt relying integrations, potentially costing organizations thousands of dollars in downtime and rework.
Why This Matters
While ideal models assume perfect adherence to API specifications, the reality of rapid software development introduces significant challenges. Teams ship frequently, coordination becomes difficult, and seemingly small changes can trigger cascading failures. Consumer-driven contract (CDC) testing mitigates this risk by focusing on actual consumer expectations rather than just the vendor’s published schema, which is how costly integration issues are prevented.
Key Insights
- CDC vs. CTK: CTKs confirm spec conformance, while consumer-driven contracts protect relying systems. Both are needed.
- Pact Adoption: Tools like Pact enable Consumer Driven Contracts, used by companies like Stripe and Coinbase.
- Backward Compatibility: A clear backward compatibility policy, including versioning and dual-writes, is essential for reliable API evolution.
Working Example
// consumer/tmf620.catalog.consumer.spec.js
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
import fetch from 'node-fetch';
const { like, term } = MatchersV3;
const provider = new PactV3({
consumer: 'CatalogUI',
provider: 'TMF620-Catalog',
});
describe('TMF620 Catalog - list productOfferings', () => {
it('returns minimal fields the UI depends on', async () => {
provider
.given('product offerings exist')
.uponReceiving('GET /productOffering?lifecycleStatus=Launched')
.withRequest({
method: 'GET',
path: '/tmf-api/productCatalogManagement/v4/productOffering',
query: { lifecycleStatus: 'Launched' }
})
.willRespondWith({
status: 200,
headers: { 'content-type': 'application/json' },
body: like([{
id: like('123'),
name: like('5G 50GB Plan'),
lifecycleStatus: term({ generate: 'Launched', matcher: '^(Launched|Active)$' }),
price: like(20),
currency: term({ generate: 'AUD', matcher: '^[A-Z]{3}$' })
}])
});
return provider.executeTest(async (mock) => {
const r = await fetch(
`${mock.url}/tmf-api/productCatalogManagement/v4/productOffering?lifecycleStatus=Launched`
);
const json = await r.json();
// assert only what the UI actually uses
expect(Array.isArray(json)).toBe(true);
expect(json[0].name).toBeTruthy();
expect(json[0].lifecycleStatus).toMatch(/^(Launched|Active)$/);
});
});
});
Practical Applications
- Use Case: Cloudnet.ai uses contract tests to ensure reliable integrations between BSS and private 5G systems.
- Pitfall: Over-asserting on contracts with unnecessary details leads to brittle tests and false failures, hindering agility.
References:
Continue reading
Next article
Terraform Provider Versioning and Compatibility
Related Content
The Complete Guide to Docker for Machine Learning Engineers
This article details how to package, run, and ship a complete machine learning prediction service using Docker, covering model training to API serving and distribution.
Stop Mocking Everything: How to Test API Resilience in Your Terminal (Curl + Chaos Proxy)
Inject 7-second delays and 503 errors into APIs using a chaos proxy, no code changes required.
Decentralizing Git: How to Prevent Collaboration Metadata Loss from Vendor Lock-in
Protect your project from account bans and platform outages by moving Git metadata to peer-to-peer networks using Radicle.