API Contract Validator for Assertion Libraries
raw JSON →The `api-contract-validator` package provides a plugin for popular JavaScript assertion libraries like Chai, Should.js, and Jest, enabling validation of API response schemas against OpenAPI (Swagger) definitions. This tool facilitates contract testing by transforming an OpenAPI definition file (YAML or JSON) into a JSON schema, which is then used to validate incoming HTTP responses. The current stable version is 2.2.8, with releases appearing to be maintenance-focused, primarily consisting of dependency upgrades rather than new features or breaking changes. Key differentiators include its plug-and-play integration with existing testing frameworks, support for various HTTP client response formats (axios, superagent, supertest, request, light-my-request), comprehensive assertion failure messages, and the ability to generate coverage reports for API contracts. It supports OpenAPI 3.0 and can handle multiple definition files, making it suitable for larger, modular API landscapes.
Common errors
error Error: definition not found for path: /api/v1/resource, method: get, status: 200 ↓
apiDefinitionsPath correctly points to your OpenAPI/Swagger file and that the file includes the definition for GET /api/v1/resource with a 200 response schema. Check for typos in path or method. error AssertionError: expected { Object (status, body, ...) } to match API schema ↓
schema for the relevant response. This often indicates a mismatch between API implementation and its documentation. error YAMLException: YAMLException: bad indentation of a mapping entry at line X, column Y ↓
Warnings
gotcha The package relies on an external OpenAPI/Swagger definition file. Errors in the definition file (e.g., invalid YAML/JSON, incorrect paths/methods) will lead to validation failures or unexpected behavior during test execution, but these errors stem from the definition, not the validator itself. Ensure your API definition is valid and accurate. ↓
gotcha This library is designed to work with specific HTTP response object structures from libraries like `axios`, `superagent`, `supertest`, and `request`. If you are using a custom HTTP client or a different library, you might need to manually construct an object with `path`, `method`, `status`, `body`, and `headers` properties to pass to `matchApiSchema`. ↓
gotcha The `api-contract-validator` package uses `api-schema-builder` internally. Frequent updates to `api-schema-builder` (as seen in recent `api-contract-validator` patch releases) suggest ongoing maintenance and potential internal changes that could subtly affect schema interpretation, although typically without breaking the public API. ↓
Install
npm install api-contract-validator yarn add api-contract-validator pnpm add api-contract-validator Imports
- chaiPlugin wrong
const matchApiSchema = require('api-contract-validator').chaiPlugin;correctimport { chaiPlugin } from 'api-contract-validator'; - shouldPlugin wrong
const matchApiSchema = require('api-contract-validator').shouldPlugin;correctimport { shouldPlugin } from 'api-contract-validator'; - jestPlugin wrong
const matchApiSchema = require('api-contract-validator').jestPlugin;correctimport { jestPlugin } from 'api-contract-validator'; - ApiContractValidator
import { ApiContractValidator } from 'api-contract-validator';
Quickstart
import { chaiPlugin } from 'api-contract-validator';
import path from 'path';
import { expect, use } from 'chai';
import supertest from 'supertest';
// Assuming a simple Express app for demonstration
const express = require('express');
const app = express();
app.get('/pet/:id', (req, res) => {
const id = parseInt(req.params.id, 10);
if (id === 123) {
res.status(200).json({ id: 123, name: 'Fido', species: 'Dog' });
} else {
res.status(404).json({ message: 'Pet not found' });
}
});
// API definitions path (assuming myApp.yaml exists relative to this file)
const apiDefinitionsPath = path.join(__dirname, 'myApp.yaml');
// add as chai plugin
use(chaiPlugin({ apiDefinitionsPath }));
const request = supertest(app);
describe('Pet API Contract', () => {
it('GET /pet/123 should match API schema', async () => {
// A dummy myApp.yaml for the quickstart
// paths:
// /pet/{id}:
// get:
// parameters:
// - in: path
// name: id
// schema:
// type: integer
// required: true
// responses:
// '200':
// description: Successful response
// content:
// application/json:
// schema:
// type: object
// properties:
// id:
// type: integer
// name:
// type: string
// species:
// type: string
// required:
// - id
// - name
// - species
const response = await request.get('/pet/123');
expect(response).to.have.status(200).and.to.matchApiSchema();
});
it('GET /pet/456 should not match API schema (e.g., 404 response)', async () => {
const response = await request.get('/pet/456');
expect(response).to.have.status(404);
// The validator would still check if the 404 response schema exists
// but in this quickstart, we're just checking the status.
// expect(response).to.matchApiSchema();
});
});