Build, Validate, Route, and Mock using OpenAPI specification. Framework-agnostic middleware tools for building APIs with the OpenAPI standard.
OpenAPI Backend sits nicely in between your framework and business logic. It can handle routing, validation and response mocking; using only standard OpenAPI specification.
Also see: openapi-client-axios
- Build APIs by describing them in OpenAPI document specification and importing them via YAML or JSON files or just passing an object
- Register handler functions for operationIds to route requests in your favourite Node.js backend
- Use JSON Schema to validate API requests and/or responses. OpenAPI Backend uses the AJV library under the hood for performant validation
- Mock API responses using OpenAPI examples objects or JSON Schema definitions
- TypeScript types included
(Currently only OpenAPI v3.0.0+ is supported)
See DOCS.md
Full example projects included in the repo
npm install --save openapi-backend
import OpenAPIBackend from 'openapi-backend';
const api = new OpenAPIBackend({
definition: {
openapi: '3.0.1',
info: {
title: 'My API',
version: '1.0.0',
},
paths: {
'/pets': {
get: {
operationId: 'getPets',
responses: {
200: { description: 'ok' },
},
},
},
'/pets/{id}': {
get: {
operationId: 'getPetById',
responses: {
200: { description: 'ok' },
},
},
parameters: [
{
name: 'id',
in: 'path',
required: true,
schema: {
type: 'integer',
},
},
],
},
},
},
handlers: {
// your platform specific request handlers here
getPets: (c, req, res) => res.status(200).json({ result: 'ok' }),
getPetById: (c, req, res) => res.status(200).json({ result: 'ok' }),
validationFail: (c, req, res) => res.status(400).json({ err: c.validation.errors }),
notFound: (c, req, res) => res.status(404).json({ err: 'not found' }),
},
});
// initalize the backend
api.init();
import express from 'express';
const app = express();
app.use(express.json());
app.use((req, res) => api.handleRequest(req, req, res));
app.listen(9000);
// API Gateway Proxy handler
module.exports.handler = (event, context) =>
api.handleRequest(
{
method: event.httpMethod,
path: event.path,
query: event.queryStringParameters,
body: event.body,
headers: event.headers,
},
event,
context,
);
See full Serverless Lambda example
module.exports = (context, req) =>
api.handleRequest(
{
method: req.method,
path: req.params.path,
query: req.query,
body: req.body,
headers: req.headers,
},
context,
req,
);
See full Azure Function example
import Hapi from 'hapi';
const server = new Hapi.Server({ host: '0.0.0.0', port: 9000 });
server.route({
method: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
path: '/{path*}',
handler: (req, h) =>
api.handleRequest(
{
method: req.method,
path: req.path,
body: req.payload,
query: req.query,
headers: req.headers,
},
req,
h,
),
});
server.start();
import Koa from 'koa';
import bodyparser from 'koa-bodyparser';
const app = new Koa();
app.use(bodyparser());
app.use((ctx) =>
api.handleRequest(
{
method: ctx.request.method,
path: ctx.request.path,
body: ctx.request.body,
query: ctx.request.query,
headers: ctx.request.headers,
},
ctx,
),
);
app.listen(9000);
Handlers are registered for operationIds
found in the OpenAPI definitions. You can register handlers as shown above with new OpenAPIBackend()
constructor opts, or using the register()
method.
async function getPetByIdHandler(c, req, res) {
const id = c.request.params.id;
const pet = await pets.getPetById(id);
return res.status(200).json({ result: pet });
}
api.register('getPetById', getPetByIdHandler);
// or
api.register({
getPetById: getPetByIdHandler,
});
Operation handlers are passed a special Context object as the first argument, which contains the parsed request, the matched API operation and input validation results. The other arguments in the example aboce are Express-specific handler arguments.
The easiest way to enable request validation in your API is to register a validationFail
handler.
function validationFailHandler(c, req, res) {
return res.status(400).json({ status: 400, err: c.validation.errors });
}
api.register('validationFail', validationFailHandler);
Once registered, this handler gets called if any JSON Schemas in either operation parameters (in: path, query, header, cookie) or requestPayload don't match the request.
The context object c
gets a validation
property with the validation result.
OpenAPIBackend doesn't automatically perform response validation for your handlers, but you can register a
postResponseHandler
to add a response validation step using validateResponse
.
api.register({
getPets: (c) => {
// when a postResponseHandler is registered, your operation handlers' return value gets passed to context.response
return [{ id: 1, name: 'Garfield' }];
},
postResponseHandler: (c, req, res) => {
const valid = c.api.validateResponse(c.response, c.operation);
if (valid.errors) {
// response validation failed
return res.status(502).json({ status: 502, err: valid.errors });
}
return res.status(200).json(c.response);
},
});
It's also possible to validate the response headers using validateResponseHeaders
.
api.register({
getPets: (c) => {
// when a postResponseHandler is registered, your operation handlers' return value gets passed to context.response
return [{ id: 1, name: 'Garfield' }];
},
postResponseHandler: (c, req, res) => {
const valid = c.api.validateResponseHeaders(res.headers, c.operation, {
statusCode: res.statusCode,
setMatchType: 'exact',
});
if (valid.errors) {
// response validation failed
return res.status(502).json({ status: 502, err: valid.errors });
}
return res.status(200).json(c.response);
},
});
Mocking APIs just got really easy with OpenAPI Backend! Register a notImplemented
handler and use mockResponseForOperation()
to generate mock responses for operations with no custom handlers specified yet:
api.register('notImplemented', (c, req, res) => {
const { status, mock } = c.api.mockResponseForOperation(c.operation.operationId);
return res.status(status).json(mock);
});
OpenAPI Backend supports mocking responses using both OpenAPI example objects and JSON Schema:
paths:
'/pets':
get:
operationId: getPets
summary: List pets
responses:
200:
$ref: '#/components/responses/PetListWithExample'
'/pets/{id}':
get:
operationId: getPetById
summary: Get pet by its id
responses:
200:
$ref: '#/components/responses/PetResponseWithSchema'
components:
responses:
PetListWithExample:
description: List of pets
content:
'application/json':
example:
- id: 1
name: Garfield
- id: 2
name: Odie
PetResponseWithSchema:
description: A single pet
content:
'application/json':
schema:
type: object
properties:
id:
type: integer
minimum: 1
name:
type: string
example: Garfield
The example above will yield:
api.mockResponseForOperation('getPets'); // => { status: 200, mock: [{ id: 1, name: 'Garfield' }, { id: 2, name: 'Odie' }]}
api.mockResponseForOperation('getPetById'); // => { status: 200, mock: { id: 1, name: 'Garfield' }}
See full Mock API example on Express
OpenAPI Backend is Free and Open Source Software. Issues and pull requests are more than welcome!