Skip to content

Commit

Permalink
Feat/docs missing tests (#4)
Browse files Browse the repository at this point in the history
* docs: add jsdoc method docs

* docs: add readme v1

* docs: update readme
  • Loading branch information
kevinccbsg authored Apr 6, 2021
1 parent 06be9dd commit 48b5216
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 20 deletions.
32 changes: 16 additions & 16 deletions .github/workflows/runTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ jobs:
- run: npm ci
- run: npm run lint
- run: npm test
# coverage:
# name: coverage
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@master
# - uses: actions/setup-node@master
# with:
# node-version: '12'
# - run: npm ci
# - uses: paambaati/[email protected]
# env:
# CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
# with:
# coverageCommand: npm test -- --coverage
# coverageLocations: |
# ${{github.workspace}}/coverage/lcov.info:lcov
coverage:
name: coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@master
with:
node-version: '12'
- run: npm ci
- uses: paambaati/[email protected]
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
with:
coverageCommand: npm test -- --coverage
coverageLocations: |
${{github.workspace}}/coverage/lcov.info:lcov
223 changes: 222 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,223 @@
[![Build](https://github.com/BRIKEV/express-oas-validator/actions/workflows/runTests.yml/badge.svg)](https://github.com/BRIKEV/express-oas-validator/actions/workflows/runTests.yml)
[![Known Vulnerabilities](https://snyk.io/test/github/BRIKEV/express-oas-validator/badge.svg)](https://snyk.io/test/github/BRIKEV/express-oas-validator)
[![Maintainability](https://api.codeclimate.com/v1/badges/13aa6d75c21855b8857c/maintainability)](https://codeclimate.com/github/BRIKEV/express-oas-validator/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/13aa6d75c21855b8857c/test_coverage)](https://codeclimate.com/github/BRIKEV/express-oas-validator/test_coverage)
![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)

# express-oas-validator
Express OpenAPI Specification (OAS) middleware validator

Express OpenAPI Specification (OAS) middleware validator and response validator.

This package will expose an express middleware that will validate your endpoint based on your OpenAPI docs, and a response validator to do the same with your responses payload.

## Installation
Install using the node package registry:

```
npm install --save express-oas-validator
```

## Usage

This is a basic usage of this package.

```js
const express = require('express');
// We recommed to install "body-parser" to validate request body
const bodyParser = require('body-parser');
const { init, validateMiddleware, responseValidation } = require('express-oas-validator');
const swaggerDefinition = require('./swaggerDefinition.json');

const app = express();

init(swaggerDefinition);
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// Middleware validator
app.post('/api/v1/songs', validateMiddleware(), (req, res) => res.send('You save a song!'));

// Middleware validator with custom configuration
app.get('/api/v1/albums/:id', validateMiddleware({ headers: false }), (req, res) => (
res.json([{
title: 'abum 1',
}])
));

// Middleware validator with custom configuration
app.get('/api/v1/authors', validateMiddleware({ body: false, query: false }), (req, res) => (
res.json([{
title: 'abum 1',
}])
));

// Response validator
app.post('/api/v1/name', (req, res, next) => {
try {
responseValidation('Error string', req, 200);
return res.send('Hello World!');
} catch (error) {
return next(error);
}
});

// Express default error handler
app.use((err, req, res, next) => {
res.status(err.status).json(err);
});
```

## methods

### init(openApiDef, options)

This methods initiates the validator so that `validateMiddleware` and `responseValidation` can be used in different files.

**Parameters**

| Name | Type | Description |
| ------------|:------:| ------------------:|
| openApiDef | object | OpenAPI definition |
| options | object | Options to extend the errorHandler or Ajv configuration |

```js
const swaggerDefinition = require('./swaggerDefinition.json');

init(swaggerDefinition);
```


## validateMiddleware(endpointConfig)


Express middleware that receives this configuration options and validates each of the options.

```js
const DEFAULT_CONFIG = {
body: true,
params: true,
headers: true,
query: true,
required: true,
};
```

**Example**

```js
// This one uses the DEFAULT_CONFIG
app.get('/api/v1/albums/:id', validateMiddleware(), (req, res) => (
res.json([{
title: 'abum 1',
}])
));

// With custom configuration
app.get('/api/v1/albums/:id', validateMiddleware({ headers: false }), (req, res) => (
res.json([{
title: 'abum 1',
}])
));
```

## responseValidation(payload, req, status)

Method to validate response payload based on the docs and the status we want to validate.

**Parameters**

| Name | Type | Description |
| ------------|:------:| ------------------:|
| payload | * | response we want to validate |
| req | object | Options to extend the errorHandler or Ajv configuration |
| status | number | esponse status we want to validate |


**Example**

```js
responseValidation('Error string', req, 200);
```

## Example with express-jsdoc-swagger

This is an example using [express-jsdoc-swagger](https://www.npmjs.com/package/express-jsdoc-swagger).

```js
const express = require('express');
const bodyParser = require('body-parser');
const expressJSDocSwagger = require('express-jsdoc-swagger');
const { init, validateMiddleware, responseValidation } = require('express-oas-validator');

const options = {
info: {
version: '1.0.0',
title: 'Albums store',
license: {
name: 'MIT',
},
},
filesPattern: './fake-server.js',
baseDir: __dirname,
};

const app = express();
const instance = expressJSDocSwagger(app)(options);

const serverApp = () => new Promise(resolve => {
instance.on('finish', data => {
init(data);
resolve(app);
});
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
/**
* A song
* @typedef {object} Song
* @property {string} title.required - The title
* @property {string} artist - The artist
* @property {integer} year - The year
*/

/**
* POST /api/v1/songs
* @param {Song} request.body.required - song info
* @return {object} 200 - song response
*/
app.post('/api/v1/songs', validateMiddleware(), (req, res) => res.send('You save a song!'));

/**
* POST /api/v1/name
* @param {string} request.body.required - name body description
* @return {object} 200 - song response
*/
app.post('/api/v1/name', (req, res, next) => {
try {
responseValidation('Error string', req);
return res.send('Hello World!');
} catch (error) {
return next(error);
}
});

/**
* GET /api/v1/authors
* @summary This is the summary or description of the endpoint
* @param {string} name.query.required - name param description - enum:type1,type2
* @param {array<string>} license.query - name param description
* @return {object} 200 - success response - application/json
*/
app.get('/api/v1/authors', validateMiddleware({ headers: false }), (req, res) => (
res.json([{
title: 'abum 1',
}])
));

// eslint-disable-next-line no-unused-vars
app.use((err, req, res, next) => {
res.status(err.status).json(err);
});
});

module.exports = serverApp;
```
34 changes: 33 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,39 @@ const getConfig = require('./utils/config');

let instance = null;

/**
* Validator methods
* @typedef {object} Options
* @property {function()} errorHandler custom error handler
* @property {object} ajvConfig Ajv config object
*/

/**
* Init method to instantiate the OpenAPI validator
* @param {object} openApiDef OpenAPI definition
* @param {Options} options Options to extend the errorHandler or Ajv configuration
*/
const init = (openApiDef, options = {}) => {
if (instance === null) {
instance = openapiValidatorUtils(openApiDef, options);
}
return instance;
};

/**
* Validator methods
* @typedef {object} EndpointConfig
* @property {boolean} body custom error handler
* @property {boolean} params Ajv config object
* @property {boolean} headers Ajv config object
* @property {boolean} query Ajv config object
* @property {boolean} required Ajv config object
*/

/**
* Endpoint configuration
* @param {EndpointConfig} endpointConfig middleware validator options
*/
const validateMiddleware = endpointConfig => (req, res, next) => {
try {
const config = getConfig(endpointConfig);
Expand Down Expand Up @@ -55,7 +81,13 @@ const validateMiddleware = endpointConfig => (req, res, next) => {
}
};

const responseValidation = (payload, status, req) => {
/**
* Method to validate response payload
* @param {*} payload response we want to validate
* @param {object} req express request object
* @param {number} status response status we want to validate
*/
const responseValidation = (payload, req, status = 200) => {
try {
const {
contentType,
Expand Down
4 changes: 2 additions & 2 deletions test/fake-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const serverApp = () => new Promise(resolve => {
*/
app.post('/api/v1/name', (req, res, next) => {
try {
responseValidation('Error string', 200, req);
responseValidation('Error string', req);
return res.send('Hello World!');
} catch (error) {
return next(error);
Expand All @@ -68,7 +68,7 @@ const serverApp = () => new Promise(resolve => {
*/
app.post('/api/v2/name', (req, res, next) => {
try {
responseValidation('Error string', 200, req);
responseValidation('Error string', req, 200);
return res.send('Hello World!');
} catch (error) {
return next(error);
Expand Down
3 changes: 3 additions & 0 deletions utils/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ const DEFAULT_CONFIG = {
required: true,
};

/**
* @param {object} config
*/
const getConfig = config => {
if (!config || Object.keys(config).length === 0) return DEFAULT_CONFIG;
return {
Expand Down
Loading

0 comments on commit 48b5216

Please sign in to comment.