Skip to content

Repository files navigation

openapi-backend

CILicensenpm versionnpm downloadsLibraries.io dependency status for latest releasenpm type definitionsBuy me a coffee

Build, Validate, Route, Authenticate, and Mock using OpenAPI definitions.

OpenAPI Backend is a Framework-agnostic middleware tool for building beautiful APIs with OpenAPI Specification.

Features

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
importOpenAPIBackendfrom'openapi-backend';// create api with your definition file or objectconstapi=newOpenAPIBackend({definition: './petstore.yml'});// register your framework specific request handlers hereapi.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 backendapi.init();

Express

importexpressfrom'express';constapp=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 handlermodule.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

importfastifyfrom'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

importHapifrom'@hapi/hapi';constserver=newHapi.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

importKoafrom'koa';importbodyparserfrom'koa-bodyparser';constapp=newKoa();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.

asyncfunctiongetPetByIdHandler(c,req,res){constid=c.request.params.id;constpet=awaitpets.getPetById(id);returnres.status(200).json({result: pet});}api.register('getPetById',getPetByIdHandler);// orapi.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.

functionvalidationFailHandler(c,req,res){returnres.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.responsereturn[{id: 1,name: 'Garfield'}];},postResponseHandler: (c,req,res)=>{constvalid=c.api.validateResponse(c.response,c.operation);if(valid.errors){// response validation failedreturnres.status(502).json({status: 502,err: valid.errors});}returnres.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.responsereturn[{id: 1,name: 'Garfield'}];},postResponseHandler: (c,req,res)=>{constvalid=c.api.validateResponseHeaders(res.headers,c.operation,{statusCode: res.statusCode,setMatchType: 'exact',});if(valid.errors){// response validation failedreturnres.status(502).json({status: 502,err: valid.errors});}returnres.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: apiKeyin: headername: x-api-keysecurity:
- ApiKey: []
api.registerSecurityHandler('ApiKey',(c)=>{constauthorized=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 valuereturnauthorized;});

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)=>{returnres.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);returnres.status(status).json(mock);});

OpenAPI Backend supports mocking responses using both OpenAPI example objects and JSON Schema:

paths:
'/pets':
get:
operationId: getPetssummary: List petsresponses:
200:
$ref: '#/components/responses/PetListWithExample''/pets/{id}':
get:
operationId: getPetByIdsummary: Get pet by its idresponses:
200:
$ref: '#/components/responses/PetResponseWithSchema'components:
responses:
PetListWithExample:
description: List of petscontent:
'application/json':
example:
- id: 1name: Garfield
- id: 2name: OdiePetResponseWithSchema:
description: A single petcontent:
'application/json':
schema:
type: objectproperties:
id:
type: integerminimum: 1name:
type: stringexample: 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 support@openapistack.co.

Contributing

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

About

Build, Validate, Route, Authenticate and Mock using OpenAPI

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages