Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
openapi-backend
Advanced tools
Build, Validate, Route, Authenticate and Mock using OpenAPI definitions. Framework-agnostic
Build, Validate, Route, Authenticate, and Mock using OpenAPI definitions.
OpenAPI Backend is a Framework-agnostic middleware tool for building beautiful APIs with OpenAPI Specification.
New! OpenAPI Backend documentation is now found on openapistack.co
https://openapistack.co/docs/openapi-backend/intro
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();
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 TypeScript example
// 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 Framework 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 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();
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();
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);
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.
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);
},
});
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 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
For assistance with integrating openapi-backend in your company, reach out at support@openapistack.co.
OpenAPI Backend is Free and Open Source Software. Issues and pull requests are more than welcome!
FAQs
Build, Validate, Route, Authenticate and Mock using OpenAPI definitions. Framework-agnostic
We found that openapi-backend demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.