Skip to main content

Reference

Class OpenAPIBackend​

OpenAPIBackend is the main class you can interact with. You can create a new instance and initialize it with your OpenAPI document and handlers.

OpenAPIBackend is also the default import of the openapi-backend module. It can be imported in any of the following ways:

import OpenAPIBackend from "openapi-backend";
import { OpenAPIBackend } from "openapi-backend";
const { OpenAPIBackend } = require("openapi-backend");
const OpenAPIBackend = require("openapi-backend").default;

new OpenAPIBackend(opts)​

Creates an instance of OpenAPIBackend and returns it.

Example:

const api = new OpenAPIBackend({
definition: "./openapi.yml",
strict: true,
quick: false,
validate: true,
ignoreTrailingSlashes: true,
ajvOpts: { unknownFormats: true },
customizeAjv: () => new Ajv(),
});

Parameter: opts​

Constructor options

Parameter: opts.definition​

The OpenAPI definition as a file path or Document object.

Type: Document | string

Parameter: opts.apiRoot​

The root URI of your api. All paths will be matched relative to apiRoot (default: "/")

Type: string

Parameter: opts.strict​

Optional. Strict mode: fail closed instead of warning (default: false)

In strict mode:

  • .init() throws on OpenAPI definition errors
  • .register() throws for unknown operationIds and security scheme names
  • .handleRequest() rejects with a 401-unauthorized: ... error when a request fails its security requirements and no unauthorizedHandler is registered, and with a 400-validationFail: ... error when a request fails validation and no validationFail handler is registered (since 5.21.0)

Without strict mode, all of these log a warning, and requests that fail their security requirements or validation still reach the operation handler. Strict mode is recommended in production. See Security Best Practices.

Type: boolean

Parameter: opts.quick​

Optional. Quick startup. Attempts to optimize startup time by skipping and deferring some parts.

This setting is recommended to optimize cold starts in Serverless Function environments such as AWS Lambda / Azure Functions / GCP Cloud Functions.

Type: boolean

Parameter: opts.validate​

Optional. Enable or disable request validation (default: true)

Setting this to false disables validation entirely and skips building the Ajv validators at startup.

You can also pass a predicate to decide per request. It receives the context object followed by the same handler arguments you pass to .handleRequest(), and validation runs only when it returns true.

const api = new OpenAPIBackend({
definition,
// skip validation for internal traffic, validate everything else
validate: (c, req: Request, res: Response) => !req.headers["x-internal-request"],
});

Type: boolean | ContextPredicate

Parameter: opts.coerceTypes​

Optional. Enable or disable coerce typing (default: false)

Coercion happens as part of validation, so it only applies to requests that actually get validated. With opts.validate: false nothing is coerced, and with a predicate the requests it skips aren't coerced either.

The effect of this is that query and path parameters will be of their specified types at run-time. In below example request.query.breed is a string and request.query.age is a number.

{
"name": "breed",
"in": "query",
"schema": {
"type": "string"
}
}
{
"name": "age",
"in": "query",
"schema": {
"type": "integer"
}
}

Type: boolean

Parameter: opts.ignoreTrailingSlashes​

Optional. Whether to ignore trailing slashes when routing (default: true)

Type: boolean

Parameter: opts.ajvOpts​

Optional. The default AJV options to use for validation. See available options

Type: AjvOpts

Parameter: opts.customizeAjv(originalAjv, ajvOpts, validationContext)​

Optional. Customizer function to use custom Ajv for validation.

Type: AjvCustomizer

Takes in three arguments

  • originalAjv the original Ajv instance created by OpenAPIBackend
  • ajvOpts the opts for the original Ajv instance
  • validationContext the context in which this Ajv instance will be used. One of:
    • 'requestBodyValidator'
    • 'paramsValidator'
    • 'responseValidator'
    • 'responseHeadersValidator'

Returns an Ajv instance.

Parameter: opts.handlers​

Optional. Operation Handlers to be registered.

Type: { [operationId: string]: Handler }

.init()​

Initializes the OpenAPIBackend instance for use.

  1. Loads and parses the OpenAPI document passed in constructor options
  2. Validates the OpenAPI document
  3. Builds validation schemas for all API operations
  4. Marks member property initialized to true
  5. Registers all Operation Handlers passed in constructor options

The init() method should be called right after creating a new instance of OpenAPIBackend. Although for ease of use, some methods like handleRequest() will call the method if the initialized member property is set to false.

Returns the initialized OpenAPI backend instance.

Example:

api.init();

.handleRequest(req, ...handlerArgs)​

Handles a request

  1. Routing: Matches the request to an API operation
  2. Validation: Validates the request against the API operation schema (skipped when .validate is set to false, or when a .validate predicate returns false for the request)
  3. Handling: Passes the request on to a registered operation handler

Example usage:

const response = await api.handleRequest(
{
method: req.method,
path: req.path,
body: req.body,
query: req.query,
headers: req.headers,
},
req,
res,
));

Parameter: req​

A request to handle.

Type: Request

Parameter: handlerArgs​

The handler arguments to be passed to the Operation Handler.

These should be the arguments you normally use when handling requests in your backend, such as the Express request and response or the Lambda event and context.

Type: any[]

.validateRequest()​

Validates a request and returns the result.

See OpenAPIValidator.validateRequest()

.validateResponse()​

Validates a response and returns the result.

See OpenAPIValidator.validateResponse()

.validateResponseHeaders()​

Validates response headers and returns the result.

See OpenAPIValidator.validateResponseHeaders()

.matchOperation()​

Matches a request to an API operation (router).

See OpenAPIRouter.matchOperation()

.register(operationId, handler)​

Registers a handler for an operation.

Example usage:

api.register('getPets', function (c, req, res) {
return {
status: 200,
body: JSON.stringify(['pet1', 'pet2']),
};
};

Parameter: operationId​

The operationId of the operation to register a handler for.

Type: string

Parameter: handler​

The operation handler.

Type: Handler | ErrorHandler

.register(handlers)​

Registers multiple Operation Handlers.

Example usage:

api.register({
getPets: (req, res) => res.json({ result: ["pet1", "pet2"] }),
notFound: (req, res) => res.status(404).json({ err: "not found" }),
validationFail: (err, req, res) => res.status(404).json({ err }),
});

Parameter: opts.handlers​

Operation Handlers to be registered.

Type: { [operationId: string]: Handler | ErrorHandler }

.mockResponseForOperation(operationId, opts?)​

Mocks a response for an operation based on example or response schema.

Returns an object with a status code and the mocked response.

Example usage:

api.registerHandler(
"notImplemented",
async (c, req: Request, res: Response) => {
const { status, mock } = api.mockResponseForOperation(
c.operation.operationId
);
return res.status(status).json(mock);
}
);

Parameter: operationId​

The operationId of the operation for which to mock the response

Type: string

Parameter: opts​

Optional. Options for mocking.

Parameter: opts.responseStatus​

Optional. The response code of the response to mock (default: 200)

Type: number

Parameter: opts.mediaType​

Optional. The media type of the response to mock (default: application/json)

Type: string

Parameter: opts.example​

Optional. The specific example to use (if operation has multiple examples)

Type: string

.registerSecurityHandler(name, handler)​

Registers a security handler for a security scheme.

Example usage:

api.registerSecurityHandler("ApiKey", (c) => {
const authorized =
c.request.headers["x-api-key"] === "SuperSecretPassword123";
return authorized;
});

See Security Handlers

Parameter: name​

The name of the Security Scheme to register a handler for.

Type: string

Parameter: handler​

The security handler.

Type: Handler | ErrorHandler

.router​

OpenAPIBackend instances expose an instance of OpenAPIRouter created during init() to be used for matching requests to their OpenAPI operations.

.validator​

OpenAPIBackend instances expose an instance of OpenAPIValidator created during init() to be used for validating schemas.

Class OpenAPIRouter​

OpenAPIRouter is an internal class that matches an abstract Request object to an OpenAPI operation.

Calling the init method creates an instance of OpenAPIRouter which can be publicly accessed via the OpenAPIBackend.router property.

The OpenAPIRouter class is exported from the openapi-backend module:

import { OpenAPIRouter } from "openapi-backend";
const { OpenAPIRouter } = require("openapi-backend");

You can also directly import the class from the submodule:

import { OpenAPIRouter } from "openapi-backend/router";

new OpenAPIRouter(opts)​

Creates an instance of OpenAPIRouter and returns it.

Example:

const router = new OpenAPIRouter({
definition: api.document,
apiRoot: "/",
ignoreTrailingSlashes: true,
});

Parameter: opts​

Constructor options

Parameter: opts.definition​

The OpenAPI definition as a Document object.

Type: Document

Parameter: opts.apiRoot​

Optional. The root URI of your api. All paths will be matched relative to apiRoot (default: "/")

Type: string

Parameter: opts.ignoreTrailingSlashes​

Optional. Whether to ignore trailing slashes when routing (default: true)

Type: string

.matchOperation(req)​

Matches a request to an API operation (router) and returns the matched Operation Object. Returns undefined if no operation was matched.

Example usage:

const operation = api.router.matchOperation({
method: "GET",
path: "/pets",
headers: { accept: "application/json" },
});

Parameter: req​

A request to match to an Operation.

Type: Request

.getOperations()​

Flattens operations into a simple array of Operation objects easy to work with.

Example usage:

const operations = api.router.getOperations();
console.log(`There are ${operations.length} operations in this api`);

.getOperation(operationId)​

Gets a single operation by its operationId.

Example usage:

const operation = api.router.getOperation("getPets");
console.log(`The tags for getPets are: ${operation.tags.join(", ")}`);

Parameter: operationId​

The operationId of the operation to get.

Type: string

.parseRequest(req, operation?)​

Parses and normalizes a request.

This method used to construct the parsed request for Context objects.

  1. Parses body into an object
  2. Parses query parameters from query string
  3. Parses cookies from the cookie header
  4. Parses path parameters from the request uri and passed operation path template
  5. Strips apiRoot from path
const parsedRequest = api.router.parseRequest(
{
method: "GET",
path: "/v1/pet/8?fields=id,name",
headers: {
accept: "application/json",
cookie: "token=abc123;path=/",
},
},
api.getOperation("getPetById")
);

assert(parsedRequest.method, "get");
assert(parsedRequest.query.fields, ["id", "name"]);
assert(parsedRequest.cookies.token, "abc123");
assert(parsedRequest.path, "/pet/8");
assert(parsedRequest.params.id, "8");

Parameter: req​

A request to parse.

Type: Request

Parameter: operation​

Optional. An operation object to match the request with. Used to parse path and query parameters according to operation spec.

Type: string

Class OpenAPIValidator​

OpenAPIValidator is an internal class for performing validations against json schemas in an OpenAPI definition.

Calling the init method creates an instance of OpenAPIValidator which can be publicly accessed via the OpenAPIBackend.validator property.

new OpenAPIValidator(opts)​

Creates an instance of OpenAPIValidator and returns it.

Example:

const validator = new OpenAPIValidator({
definition: api.document,
router: new OpenAPIRouter()
ajvOpts: { unknownFormats: true },
lazyCompileValidators: false,
customizeAjv: (originalAjv, ajvOpts, validationContext) => new Ajv(),
});

The OpenAPIValidator class is exported from the openapi-backend module:

import { OpenAPIValidator } from "openapi-backend";
const { OpenAPIValidator } = require("openapi-backend");

You can also directly import the class from the submodule:

import { OpenAPIValidator } from "openapi-backend/validation";

Parameter: opts​

Constructor options

Parameter: opts.definition​

The OpenAPI definition as a Document object.

Type: Document

Parameter: opts.ajvOpts​

Optional. The default AJV options to use for validation. See available options

Type: AjvOpts

Parameter: opts.router​

Optional. Passed instance of OpenAPIRouter. Will create new instance from definition object if not passed.

Type: OpenAPIRouter

Parameter: opts.lazyCompileValidators​

Optional. When set to true skips precompiling Ajv validators and compiles only when needed. Useful for optimizing for init time e.g. in Lambda.

This option is applied when the OpenAPIBackend quick parameter is set to true.

Type: Boolean

Parameter: opts.customizeAjv(originalAjv, ajvOpts, validationContext)​

Optional. Customizer function to use custom Ajv for validation.

Type: AjvCustomizer

Takes in three arguments

  • originalAjv the original Ajv instance created by OpenAPIBackend
  • ajvOpts the opts for the original Ajv instance
  • validationContext the context in which this Ajv instance will be used. One of:
    • 'requestBodyValidator'
    • 'paramsValidator'
    • 'responseValidator'
    • 'responseHeadersValidator'

Returns an Ajv instance.

.validateRequest(req, operation?)​

Validates a request and returns the result.

The method will first match the request to an API operation and use the pre-compiled Ajv validation schema to validate it.

Normally, you wouldn't need to explicitly call .validateRequest() because .handleRequest() calls it for you when validation is set to true. But if you like, you can use it to just do request validation separately from handling.

Returns a ValidationResult object.

Example usage:

const valid = api.validateRequest({
method: req.method,
path: req.path,
body: req.body,
query: req.query,
headers: req.headers,
});
if (valid.errors) {
// there were errors
}

Parameter: req​

A request to validate.

Type: Request

Parameter: operation​

Optional. The Operation object or operationId to validate against.

If omitted, .matchOperation() will be used to match the operation first.

Type: Operation or string (operationId)

.validateResponse(res, operation, statusCode?)​

Validates a response and returns the result.

The method will use the pre-compiled Ajv validation schema to validate the given response.

You can optionally provide a status code for more accurate validation.

Returns a ValidationResult object.

Example usage:

const valid = api.validateResponse({ name: "Garfield" }, "getPetById");
if (valid.errors) {
// there were errors
}
const valid = api.validateResponse({ name: "Unknown" }, "getPetById", 200);
if (valid.errors) {
// there were errors
}

Parameter: res​

The response to validate.

Type: any

Parameter: operation​

The Operation object or operationId to validate against.

Type: Operation or string

Parameter: statusCode​

The HTTP response status code.

Type: number

.validateResponseHeaders(headers, operation, opts?)​

Validates response headers and returns the result.

The method will use the pre-compiled Ajv validation schema to validate the given response.

Returns a ValidationResult object.

Example usage:

const valid = api.validateResponseHeaders(
{
"Content-Type": "text/plain",
},
"getPetById",
{
statusCode: 200,
setMatchType: "exact",
}
);
if (valid.errors) {
// there were errors
}

Parameter: headers​

The response headers to validate.

Type: any

Parameter: operation​

The Operation object or operationId to validate against.

Type: Operation or string

Parameter: opts​

Optional. Options for validate the response headers.

Parameter: opts.statusCode​

Optional. The status code of the response.

Type: number

Parameter: opts.setMatchType​

Optional. The type of set matching to perform, in relation with the set of headers defined in your spec. It can be any, superset, subset or exact. Defaults to any.

  • any: Skip checks for missing or additional headers. It only checks that the types of the headers are matching with the spec.
  • superset: Check that headers is a superset of the headers defined in your spec. In other words, you can have headers in headers that are described in your spec.
  • subset: Check that headers is a subset of the headers defined in your spec. In other words, you can have headers in you spec that are not present in headers.
  • exact: Check that headers exactly match the headers defined in your spec.

Type: SetMatchType

Operation Handlers​

You can register Operation Handlers for operationIds specified by your OpenAPI document.

These get called with the .handleRequest() method after routing and (optionally) validation is finished.

The first argument of the handler is the Context object and rest are passed from .handleRequest() arguments, starting from the second one.

Example handler for Express

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);

There are two different ways to register operation handlers:

  1. In the new OpenAPIBackend constructor options
  2. With the .register() method

In addition to the operationId handlers, you should also specify special handlers for different situtations:

validationFail Handler​

The validationFail handler gets called by .handleRequest() if the input validation fails for a request.

HINT: You should probably return a 400 status code from this handler.

If no validationFail handler is registered and strict mode is off, requests that fail validation still reach the operation handler. Check c.validation.valid there, or set strict: true.

Example handler:

function validationFailHandler(c, req, res) {
return res.status(400).json({ status: 400, err: c.validation.errors });
}
api.register("validationFail", validationFailHandler);

notFound Handler​

The notFound handler gets called by .handleRequest() if the path doesn't match an operation in the API definitions.

HINT: You should probably return a 404 status code from this handler.

Example handler:

function notFound(c, req, res) {
return res.status(404).json({ status: 404, err: "Not found" });
}
api.register("notFound", notFound);

methodNotAllowed Handler​

The methodNotAllowed handler gets called by .handleRequest() if request method does not match any operations for the path.

If this handler isn't registered, the notFound Handler will be used instead.

HINT: You should probably return a 405 status code from this handler.

Example handler:

function methodNotAllowed(c, req, res) {
return res.status(405).json({ status: 405, err: "Method not allowed" });
}
api.register("methodNotAllowed", methodNotAllowed);

notImplemented Handler​

The notImplemented handler gets called by .handleRequest() if no other Operation Handler has been registered for the matched operation.

HINT: You can either mock the response or return a 501 status code.

Example handler:

function notImplementedHandler(c, req, res) {
return res
.status(404)
.json({ status: 501, err: "No handler registered for operation" });
}
api.register("notImplemented", notImplementedHandler);

unauthorizedHandler Handler​

The unauthorizedHandler handler gets called by .handleRequest() if security requirements are not met after checking Security Requirements and calling their Security Handlers.

HINT: You should probably return a 401 or 403 code from this handler and instruct the client to authenticate.

Example handler:

function unauthorizedHandler(c, req, res) {
return res
.status(401)
.json({ status: 401, err: "Please authenticate first" });
}
api.register("unauthorizedHandler", unauthorizedHandler);

If no unauthorizedHandler is registered, the Security Handlers will still be called and their output and the authorization status for the request can be checked in operation handlers via the context.security property.

In that case, unless strict mode is on, the operation handler runs even for unauthorized requests, and has to check c.security.authorized itself. See Security Best Practices.

postResponseHandler Handler​

The postResponseHandler handler gets called by .handleRequest() after resolving the response handler.

The return value of the response handler will be passed in the context object response property.

HINT: You can use the postResponseHandler to validate API responses against your response schema

Example handler:

function 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);
}
api.register("postResponseHandler", postResponseHandler);

Interfaces​

The openapi-backend module exports type definitions for TypeScript users. You can import them like you would normally.

Document Object​

The Document interface is a JavaScript object representation of an OpenAPI specification document.

OpenAPIBackend uses type definitions from openapi-types, but re-exports the Document interface for ease of use.

NOTE: Only OpenAPI v3+ documents are currently supported.

import { Document } from "openapi-backend";

An example Document Object:

const document: Document = {
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",
},
},
],
},
},
};

Operation Object​

The Operation interface is an OpenAPI Operation Object extended with the path and method of the operation for easier use. It should also include the path base object's parameters in its parameters property.

All JSON schemas in an Operation Object should be dereferenced i.e. not contain any $ref properties.

import { Operation } from "openapi-backend";

Example object

const operation: Operation = {
method: "patch",
path: "/pets/{id}",
operationId: "updatePetById",
parameters: [
{
name: "id",
in: "path",
required: true,
schema: {
type: "integer",
minimum: 0,
},
},
],
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
additionalProperties: false,
properties: {
name: {
type: "string",
},
age: {
type: "integer",
},
},
},
},
},
},
responses: {
200: {
description: "Pet updated successfully",
},
},
};

Context Object​

The Context object gets passed to Operation Handlers as the first argument.

It contains useful information like the parsed request, the matched operation, security handler results and input validation results for the request.

The context object also contains a reference to the OpenAPIBackend instance in api property for easy access to instance methods inside handlers.

import { Context } from "openapi-backend";

Example object

const context: Context = {
// reference to OpenAPIBackend instance
// can be used to access instance OpenAPI instance methods in handlers:
// - api.validateRequest()
// - api.validateResponse()
// - api.mockResponseForOperation()
api,
// the parsed request object
request: {
method: "post",
path: "/pets/1/treat",
params: { id: "1" },
headers: { accept: "application/json", cookie: "sessionid=abc123;" },
cookies: { sessionid: "abc123" },
query: { format: "json" },
body: '{ "treat": "bone" }',
requestBody: { treat: "bone" },
},
// the matched and dereferenced operation object for request
operation: {
method: "post",
path: "/pets",
operationId: "giveTreatToPetById",
summary: "Gives a treat to a pet",
description: "Adds a treat to the bowl where a pet can enjoy it.",
tags: ["pets"],
parameters: {
name: "id",
in: "path",
required: true,
schema: {
type: "integer",
},
},
requestBody: {
description: "A treat to give to the pet",
content: {
"application/json": {
schema: {
type: "object",
additionalProperties: false,
properties: {
treat: {
type: "string",
},
},
required: ["treat"],
},
},
},
},
},
// Ajv validation results for request
validation: {
valid: true,
errors: null,
},
// Security handlers results for request
security: {
authorized: true,
jwt: {
name: "John Doe",
email: "john@example.com",
iat: 1516239022,
},
basicAuth: false,
},
// Return value from operation handler (only passed to postResponseHandler)
response: {
message: "woof! thanks for the treat",
},
};

Request Object​

The Request interface represents a generic HTTP request.

import { Request } from "openapi-backend";

Example object

const request: Request = {
// HTTP method of the request
method: "POST",
// path of the request
path: "/pets/1/treat",
// HTTP request headers
headers: { accept: "application/json", cookie: "sessionid=abc123;" },
// parsed query parameters (optional), we also parse query params from the path property
query: { format: "json" },
// the request body (optional), either raw buffer/string or a parsed object/array
body: { treat: "bone" },
};

ParsedRequest Object​

The ParsedRequest interface represents a generic parsed HTTP request.

import { ParsedRequest } from "openapi-backend";

Example object

const parsedRequest: ParsedRequest = {
// HTTP method of the request (in lowercase)
method: "post",
// path of the request
path: "/pets/1/treat",
// the path params for the request
params: { id: "1" },
// HTTP request headers
headers: { accept: "application/json", cookie: "sessionid=abc123;" },
// the parsed cookies
cookies: { sessionid: "abc123" },
// parsed query parameters (optional), we also parse query params from the path property
query: { format: "json" },
// the request body (optional), either raw buffer/string or a parsed object/array
body: '{ "treat": "bone" }',
// the parsed request body
requestBody: { treat: "bone" },
};

ValidationResult Object​

The ValidationResult interface is an object containing the results from performed json schema validation.

The valid property is a boolean that tells you whether the validation succeeded (true) or not (false).

The errors property is an array of Ajv ErrorObjects from the performed validation. If no errors were found, this property will be null.

import { ValidationResult } from "openapi-backend";

Example object

const validationResult: ValidationResult = {
valid: false,
errors: [
{
keyword: "parse",
dataPath: "",
schemaPath: "#/requestBody",
params: [],
message: "Unable to parse JSON request body",
},
],
};