npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

openapi-backend

v5.11.1

Published

Build, Validate, Route, Authenticate and Mock using OpenAPI definitions. Framework-agnostic

Downloads

157,282

Readme

CI License npm version npm downloads Libraries.io dependency status for latest release npm type definitions Buy me a coffee

Features

  • [x] Build APIs by describing them in OpenAPI specification
  • [x] Register handlers for operationIds to route requests in your favourite Node.js backend
  • [x] Use JSON Schema to validate API requests and/or responses. OpenAPI Backend uses the AJV library under the hood for performant validation
  • [x] Register Auth / Security Handlers for OpenAPI Security Schemes to authorize API requests
  • [x] Auto-mock API responses using OpenAPI examples objects or JSON Schema definitions
  • [x] Built with TypeScript, types included
  • [x] Optimised runtime routing and validation. No generated code!
  • [x] OpenAPI 3.1 support

Documentation

New! OpenAPI Backend documentation is now found on openapistack.co

https://openapistack.co/docs/openapi-backend/intro

Quick Start

Full example projects included in the repo

npm install --save openapi-backend
import OpenAPIBackend from 'openapi-backend';

// create api with your definition file or object
const api = new OpenAPIBackend({ definition: './petstore.yml' });

// register your framework specific request handlers here
api.register({
  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();

Express

import express from 'express';

const app = express();
app.use(express.json());
app.use((req, res) => api.handleRequest(req, req, res));
app.listen(9000);

See full Express example

See full Express TypeScript example

AWS Serverless (Lambda)

// 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 AWS SAM example

See full AWS CDK example

See full SST example

See full Serverless Framework example

Azure Function

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

Fastify

import fastify from 'fastify';

fastify.route({
  method: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
  url: '/*',
  handler: async (request, reply) =>
    api.handleRequest(
      {
        method: request.method,
        path: request.url,
        body: request.body,
        query: request.query,
        headers: request.headers,
      },
      request,
      reply,
    ),
});
fastify.listen();

See full Fastify example

Hapi

import Hapi from '@hapi/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();

See full Hapi example

Koa

import Koa from 'koa';
import bodyparser from 'koa-bodyparser';

const app = new Koa();

app.use(bodyparser());
app.use((ctx) =>
  api.handleRequest(
    ctx.request,
    ctx,
  ),
);
app.listen(9000);

See full Koa example

Registering Handlers for Operations

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 above are Express-specific handler arguments.

Request validation

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.

Response validation

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

Auth / Security Handlers

If your OpenAPI definition contains Security Schemes you can register security handlers to handle authorization for your API:

components:
  securitySchemes:
  - ApiKey:
      type: apiKey
      in: header
      name: x-api-key
security:
  - ApiKey: []
api.registerSecurityHandler('ApiKey', (c) => {
  const authorized = c.request.headers['x-api-key'] === 'SuperSecretPassword123';
  // truthy return values are interpreted as auth success
  // you can also add any auth information to the return value
  return authorized;
});

The authorization status and return values of each security handler can be accessed via the Context Object

You can also register an unauthorizedHandler to handle unauthorized requests.

api.register('unauthorizedHandler', (c, req, res) => {
  return res.status(401).json({ err: 'unauthorized' })
});

See examples:

Mocking API responses

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

Commercial support

For assistance with integrating openapi-backend in your company, reach out at [email protected].

Contributing

OpenAPI Backend is Free and Open Source Software. Issues and pull requests are more than welcome!