Skip to main content

On This Page

Contract-Testing TM Forum Open APIs with Pact + Postman: Stop Breaking Your BSS

2 min read
Share

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