Skip to main content

Reference

Class OpenAPIBackend

OpenAPIBackend is the main class you can interact with. You can create a new instance and initalize 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, throw errors or warn on OpenAPI spec validation errors (default: false)

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)

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

Initalizes the OpenAPIBackend instace 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 initalized 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 initalized member property is set to false.

Returns the initalized 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)
  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.

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.

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 succesfully",
},
},
};

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",
},
],
};