Skip to content

ozers/contractlens

πŸ” ContractLens

Catch API breaking changes before your users do.

Lightweight runtime API contract validation for Node.js. Like Pact, but you add it in one line.

npm CI License: MIT TypeScript

Quick Start Β· Features Β· Modes Β· Pact vs ContractLens


The Problem

You have microservices. They talk to each other via APIs. One team changes a response field. The other team's service breaks. Nobody knew until production was on fire.

Pact solves this but needs a broker, consumer tests, provider tests, and weeks of setup. express-openapi-validator validates requests within a single service, not the contract between services.

ContractLens sits in your Express app, watches every response, and tells you the moment your API drifts from its OpenAPI spec.

Quick Start

npm install contractlens
import express from 'express';
import { contractlens } from 'contractlens';

const app = express();

// One line. That's it.
app.use(contractlens({ spec: './openapi.yaml' }));

app.get('/users/:id', (req, res) => {
  res.json({ id: 1, name: 'Γ–zer', role: 'backend' });
});

app.listen(3000);

If /users/:id response doesn't match your OpenAPI spec:

⚠️  ContractLens Drift Detected
β”œβ”€ GET /users/123 β†’ 200
β”œβ”€ πŸ”΄ Missing field: "email" (required in spec)
β”œβ”€ ⚠️  Extra field: "role" (not in spec)
└─ Summary: 1 breaking, 1 warning

Features

  • πŸ”΄ Missing field detection β€” Spec says email is required, response doesn't have it? Breaking.
  • ⚠️ Extra field detection β€” Response has cache_key not in spec? Warning.
  • πŸ”΄ Type mismatch β€” Spec says id: integer, response has "123"? Breaking.
  • πŸ”΄ Enum violation β€” Spec says status: active|inactive, response has "deleted"? Breaking.
  • πŸ“‘ Webhook alerts β€” Send drift reports to Slack, PagerDuty, or any URL.
  • ⚑ Production sampling β€” Validate 1% of requests, not all. Zero perf impact.
  • 🎯 Express middleware β€” Drop it in, it works. No config files, no brokers, no setup.

Modes

// Development: log warnings to console
app.use(contractlens({ spec: './openapi.yaml', mode: 'warn' }));

// CI/Staging: throw error on drift (fail fast)
app.use(contractlens({ spec: './openapi.yaml', mode: 'strict' }));

// Production: sample 1% of requests, alert via webhook
app.use(contractlens({
  spec: './openapi.yaml',
  mode: 'log',
  sampleRate: 0.01,
  reporters: ['webhook'],
  webhookUrl: 'https://hooks.slack.com/services/...'
}));

What It Catches

Drift Type Example Severity
Missing required field Spec requires email, response doesn't have it πŸ”΄ Breaking
Extra field Response has cache_key, spec doesn't define it ⚠️ Warning
Type mismatch Spec says age: integer, response returns "25" πŸ”΄ Breaking
Enum violation Spec says status: active|inactive, response has "deleted" πŸ”΄ Breaking

Configuration

contractlens({
  // Required: path to OpenAPI spec or inline object
  spec: './openapi.yaml',

  // 'warn' (default) | 'strict' | 'log'
  mode: 'warn',

  // Fraction of requests to validate (0.0 - 1.0)
  sampleRate: 1.0,

  // Reporter types
  reporters: ['console', 'webhook'],

  // Webhook URL for drift alerts
  webhookUrl: 'https://...',

  // Paths to skip validation
  exclude: ['/health', '/metrics'],
});

Pact vs ContractLens

Pact ContractLens
Setup time Hours (broker, consumer/provider tests) 1 minute (one middleware line)
Approach Consumer-driven contracts Spec-driven runtime validation
Where it runs CI/CD pipeline Runtime (dev/staging/prod)
Catches drift in Next CI run Next request
Learning curve Steep Near zero
Dependencies Pact broker, language-specific libs Just your OpenAPI spec
Best for Large teams, complex contract workflows Teams who already have OpenAPI specs

ContractLens doesn't replace Pact β€” it complements it. Use Pact for formal contract workflows, use ContractLens for instant runtime drift detection.

How It Works

Request β†’ Your Handler β†’ Response
                            ↓
                      ContractLens
                      β”œβ”€ Load OpenAPI spec (cached)
                      β”œβ”€ Match route + status code
                      β”œβ”€ Validate response against schema
                      β”œβ”€ Detect drift (extra/missing/type/enum)
                      └─ Report via console/webhook

ContractLens intercepts res.json() after the response is sent (non-blocking in warn/log mode), so it adds zero latency to your API responses.

Examples

The examples/ directory contains runnable demos for common scenarios:

Example Description
basic-usage.ts Warn mode β€” logs drift to console, doesn't block responses
strict-mode.ts Strict mode β€” returns 500 on contract drift (CI/staging)
production-setup.ts Sampling + webhook alerts + path exclusion
custom-reporter.ts Implement the Reporter interface for custom logging
git clone https://github.com/ozers/contractlens.git
cd contractlens
npm install && npm run build
npx ts-node examples/basic-usage.ts

Requirements

  • Node.js >= 20
  • Express >= 4.0
  • An OpenAPI 3.0.x or 3.1.x specification

Contributing

Contributions are welcome! Please check out the issues page.

git clone https://github.com/ozers/contractlens.git
cd contractlens
npm install
npm run test
npm run build

License

MIT


Built by Ozer β€” a backend engineer who learned the hard way that a "harmless" field rename can take down three microservices on a Friday afternoon.

About

Catch API breaking changes before your users do. Lightweight runtime API contract validation for Express.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors