Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

hapi-swagger

Package Overview
Dependencies
Maintainers
1
Versions
163
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hapi-swagger - npm Package Compare versions

Comparing version 3.1.0 to 3.1.1

35

bin/routes.js
'use strict';
const Joi = require('joi');
const js2xmlparser = require('js2xmlparser');

@@ -104,2 +105,20 @@

/**
* allows a reply to have either a json or xml response
*
* @param {String} name
* @param {Object} json
* @param {Object} request
* @param {Object} reply
*/
const replyByType = function (name, json, request, reply) {
if (request.headers.accept === 'application/xml') {
reply(js2xmlparser(name, json)).type('application/xml');
} else {
reply(json).type('application/json');
}
};
/**
* mock handler for routes

@@ -130,8 +149,8 @@ *

if (request.path.indexOf('/sum/') > -1) {
reply({ 'equals': 43 });
replyByType('result', { 'equals': 43 }, request, reply);
} else {
if (request.path === '/store/' && request.method === 'get') {
reply(list);
replyByType('list', list, request, reply);
} else {
reply(sum);
replyByType('sum', sum, request, reply);
}

@@ -303,3 +322,5 @@ }

payloadType: 'form',
nickname: 'storeit'
produces: ['application/json', 'application/xml'],
consumes: ['application/json', 'application/xml']
}

@@ -321,3 +342,3 @@ },

.default('+')
.valid(['+','-','/','*'])
.valid(['+', '-', '/', '*'])
.description('the opertator i.e. + - / or *'),

@@ -363,3 +384,3 @@

.default('+')
.valid(['+','-','/','*'])
.valid(['+', '-', '/', '*'])
.description('the opertator i.e. + - / or *'),

@@ -420,3 +441,3 @@

.default('+')
.valid(['+','-','/','*'])
.valid(['+', '-', '/', '*'])
.description('the opertator i.e. + - / or *'),

@@ -423,0 +444,0 @@

4

lib/builder.js

@@ -24,5 +24,3 @@ 'use strict';

'host': 'localhost',
'basePath': '/',
'consumes': ['application/json'],
'produces': ['application/json']
'basePath': '/'
};

@@ -29,0 +27,0 @@

@@ -46,5 +46,5 @@ 'use strict';

*/
paths.build = function ( settings, routes ){
paths.build = function (settings, routes) {
Responses.build({},{},{},{});
Responses.build({}, {}, {}, {});

@@ -54,5 +54,5 @@ let routesData = [];

// loop each route
routes.forEach( (route) => {
routes.forEach((route) => {
let routeOptions = Hoek.reach(route,'settings.plugins.hapi-swagger') || {};
let routeOptions = Hoek.reach(route, 'settings.plugins.hapi-swagger') || {};
let routeData = {

@@ -63,13 +63,15 @@ path: route.path,

notes: route.settings.notes,
tags: Hoek.reach(route,'settings.tags'),
queryParams: Hoek.reach(route,'settings.validate.query'),
pathParams: Hoek.reach(route,'settings.validate.params'),
payloadParams: Hoek.reach(route,'settings.validate.payload'),
responseSchema: Hoek.reach(route,'settings.response.schema'),
responseStatus: Hoek.reach(route,'settings.response.status'),
headerParams: Hoek.reach(route,'settings.validate.headers'),
responses: Hoek.reach(routeOptions,'responses') || {},
nickname: Hoek.reach(routeOptions,'nickname') || null,
payloadType: Hoek.reach(routeOptions,'payloadType') || null,
security: Hoek.reach(routeOptions,'security') || null,
tags: Hoek.reach(route, 'settings.tags'),
queryParams: Hoek.reach(route, 'settings.validate.query'),
pathParams: Hoek.reach(route, 'settings.validate.params'),
payloadParams: Hoek.reach(route, 'settings.validate.payload'),
responseSchema: Hoek.reach(route, 'settings.response.schema'),
responseStatus: Hoek.reach(route, 'settings.response.status'),
headerParams: Hoek.reach(route, 'settings.validate.headers'),
consumes: Hoek.reach(routeOptions, 'consumes') || null,
produces: Hoek.reach(routeOptions, 'produces') || null,
responses: Hoek.reach(routeOptions, 'responses') || null,
nickname: Hoek.reach(routeOptions, 'nickname') || null,
payloadType: Hoek.reach(routeOptions, 'payloadType') || null,
security: Hoek.reach(routeOptions, 'security') || null,
groups: route.group

@@ -80,16 +82,16 @@ };

// user configured interface through route plugin options
if (Hoek.reach(routeOptions, 'validate.query')){
routeData.queryParams = Properties.joiObjectToArray( Hoek.reach(routeOptions, 'validate.query') );
if (Hoek.reach(routeOptions, 'validate.query')) {
routeData.queryParams = Properties.joiObjectToArray(Hoek.reach(routeOptions, 'validate.query'));
}
if (Hoek.reach(routeOptions,'validate.params')){
routeData.pathParams = Properties.joiObjectToArray( Hoek.reach(routeOptions,'validate.params') );
if (Hoek.reach(routeOptions, 'validate.params')) {
routeData.pathParams = Properties.joiObjectToArray(Hoek.reach(routeOptions, 'validate.params'));
}
if (Hoek.reach(routeOptions, 'validate.headers')){
routeData.headerParams = Properties.joiObjectToArray( Hoek.reach(routeOptions, 'validate.headers') );
if (Hoek.reach(routeOptions, 'validate.headers')) {
routeData.headerParams = Properties.joiObjectToArray(Hoek.reach(routeOptions, 'validate.headers'));
}
if (Hoek.reach(routeOptions, 'validate.payload')){
if (Hoek.reach(routeOptions, 'validate.payload')) {
// has different structure, just pass straight through
routeData.payloadParams = Hoek.reach(routeOptions, 'validate.payload' );
// if its a native javascript object convert it to JOI
if (!routeData.payloadParams.isJoi){
routeData.payloadParams = Hoek.reach(routeOptions, 'validate.payload');
// if its a native javascript object convert it to JOI
if (!routeData.payloadParams.isJoi) {
routeData.payloadParams = Joi.object(routeData.payloadParams);

@@ -100,7 +102,7 @@ }

// hapi wildcard method support
if (routeData.method === '*'){
if (routeData.method === '*') {
// OPTIONS not supported by Swagger and HEAD not support by HAPI
['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].forEach( (method) => {
['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].forEach((method) => {
var newRoute = Hoek.clone( routeData );
var newRoute = Hoek.clone(routeData);
newRoute.method = method.toUpperCase();

@@ -115,3 +117,3 @@ routesData.push(newRoute);

return paths.properties( settings, routesData);
return paths.properties(settings, routesData);
};

@@ -127,3 +129,3 @@

*/
paths.properties = function ( settings, routes ){
paths.properties = function (settings, routes) {

@@ -136,3 +138,3 @@ let pathObj = {};

routes.forEach( (route) => {
routes.forEach((route) => {

@@ -152,15 +154,27 @@ let method = route.method;

if (route.security){
if (route.security) {
out.security = route.security;
}
let payloadParameters;
// set from plugin options or from route options
let payloadType = internals.overload(settings.payloadType, route.payloadType);
let consumes = internals.overload(settings.consumes, route.consumes);
let produces = internals.overload(settings.consumes, route.produces);
// set from plugin options or from route options
let payloadType = settings.payloadType;
if (route.payloadType){
payloadType = route.payloadType;
if (route.consumes) {
out.consumes = route.consumes;
}
if (route.produces) {
out.produces = route.produces;
}
// use mimetype to override payloadType
if (Array.isArray(consumes)
&& (consumes.indexOf('application/x-www-form-urlencoded') > -1
|| consumes.indexOf('multipart/form-data') > -1)) {
payloadType = 'form';
}
// build payload either with JSON or form input
let payloadParameters;
if (payloadType.toLowerCase() === 'json') {

@@ -174,3 +188,3 @@

// override inline structure and use defination object
if (payloadParameters && payloadParameters.type !== 'void'){
if (payloadParameters && payloadParameters.type !== 'void') {
payloadParameters.in = 'body';

@@ -191,14 +205,28 @@ payloadParameters.name = 'body';

} else {
payloadParameters = Properties.toParameters( internals.getJOIObj(route, 'payloadParams'), swagger.definitions, 'formData' );
payloadParameters = Properties.toParameters(internals.getJOIObj(route, 'payloadParams'), swagger.definitions, 'formData');
// add form mimetype
out.consumes = (out.consumes) ? out.consumes : [];
if (out.consumes.indexOf('application/x-www-form-urlencoded') === -1) {
out.consumes = ['application/x-www-form-urlencoded'];
}
}
out.parameters = out.parameters.concat(
Properties.toParameters( internals.getJOIObj(route, 'headerParams'), swagger.definitions, 'header' ),
Properties.toParameters( internals.getJOIObj(route, 'pathParams'), swagger.definitions, 'path' ),
Properties.toParameters( internals.getJOIObj(route, 'queryParams'), swagger.definitions, 'query' )
);
if (payloadParameters){
out.parameters = out.parameters.concat( payloadParameters );
Properties.toParameters(internals.getJOIObj(route, 'headerParams'), swagger.definitions, 'header'),
Properties.toParameters(internals.getJOIObj(route, 'pathParams'), swagger.definitions, 'path'),
Properties.toParameters(internals.getJOIObj(route, 'queryParams'), swagger.definitions, 'query')
);
if (payloadParameters) {
out.parameters = out.parameters.concat(payloadParameters);
}
// change form mimetype based on meta property 'swaggerType'
if (internals.hasFileType(route)) {
out.consumes = (out.consumes) ? out.consumes : [];
// add to front of array so swagger-ui picks it up
if (out.consumes.indexOf('multipart/form-data') === -1) {
out.consumes = ['multipart/form-data'];
}
}
//let name = out.operationId + method;

@@ -213,3 +241,3 @@ out.responses = Responses.build(

if (!pathObj[path]){
if (!pathObj[path]) {
pathObj[path] = {};

@@ -225,3 +253,9 @@ }

// gets the JOI object from route object
/**
* gets the JOI object from route object
*
* @param {Object} base
* @param {String} name
* @return {Object}
*/
internals.getJOIObj = function (route, name) {

@@ -235,1 +269,27 @@

};
/**
* overload one object with another
*
* @param {Object} base
* @param {Object} priority
* @return {Object}
*/
internals.overload = function (base, priority) {
return (priority) ? priority : base;
};
/**
* does route have property swaggerType of file
*
* @param {Object} route
* @return {Boolean}
*/
internals.hasFileType = function (route) {
let routeString = JSON.stringify(route);
return routeString.indexOf('swaggerType') > -1;
};
{
"name": "hapi-swagger",
"description": "A swagger documentation UI generator plugin for hapi",
"version": "3.1.0",
"version": "3.1.1",
"author": "Glenn Jones",

@@ -41,3 +41,4 @@ "repository": {

"h2o2": "4.0.1",
"hapi-auth-bearer-token": "4.0.0"
"hapi-auth-bearer-token": "4.0.0",
"js2xmlparser": "1.0.0"
},

@@ -44,0 +45,0 @@ "scripts": {

@@ -22,3 +22,3 @@ # hapi-swagger

If you want to view the documentation from your API you will also need to install the `inert` and `vision` plugs-ins which support templates and static
content serving. If you wish just to used swagger.json without the documentation for example with swagger-codegen simply set `enableDocumentation` to false
content serving. If you wish just to used swagger.json without the documentation for example with swagger-codegen simply set `enableDocumentation` to `false`.

@@ -109,4 +109,5 @@ $ npm install inert --save

* `expanded`: (boolean) If UI is expanded when opened - default: `true`
* `sortPaths`: (string) the path sort method for JSON. `unsorted` or `path-method`,
* `lang`: (string) The language of the UI either `en`, `es`, `pt` or `ru` - default: `en`
* `tags`: (object) Containing [Tag Object] (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#tagObject) used to group endpoints in swagger-ui.
* `tags`: (object) Containing [Tag Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#tagObject) used to group endpoints in swagger-ui.
* `securityDefinitions:`: (array) Containing [Security Definitions Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#securityDefinitionsObject). No defaults are provided.

@@ -151,4 +152,28 @@

### Grouping endpoints with tags
Swagger provides a tag object which allows you to group your endpoints in the swagger-ui interface. The name of the tag needs to match path of your endpoinds, so in the example below all enpoints with the path `/store` and `/sum` will be group togther.
```Javascript
let swaggerOptions = {
info: {
'title': 'Test API Documentation',
'version': Pack.version,
},
tags: [{
'name': 'store',
'description': 'Storing a sum',
'externalDocs': {
'description': 'Find out more about storage',
'url': 'http://example.org'
}
}, {
'name': 'sum',
'description': 'API of sums',
'externalDocs': {
'description': 'Find out more about sums',
'url': 'http://example.org'
}
}]
};
```
### Route option example

@@ -288,3 +313,3 @@ The route level options are always placed within the `plugins.hapi-swagger` object under `config`. These options are only assigned to the route they are apply to.

### Naming
There are times when you may wish to name a object so that its label in the Swagger interface make more sense to humans. This is most common when you have endpoint which take JSON structures. To label a object simply wrap it as a JOI object and chain the label function as below.
There are times when you may wish to name a object so that its label in the Swagger interface make more sense to humans. This is most common when you have endpoint which take JSON structures. To label a object simply wrap it as a JOI object and chain the label function as below. __You need to give different structure its own unique name.__
```Javascript

@@ -467,2 +492,2 @@ validate: {

### Issues
If you find any issue please file here on github and I will try and fix them.
If you find any issue please file here on github and I will try and fix them.

@@ -34,4 +34,4 @@ 'use strict';

expect(response.result.basePath).to.equal('/');
expect(response.result.consumes).to.deep.equal(['application/json']);
expect(response.result.produces).to.deep.equal(['application/json']);
expect(response.result.consumes).to.not.exist();
expect(response.result.produces).to.not.exist();
done();

@@ -50,4 +50,4 @@ });

'basePath': '/base',
'consumes': ['application/xml'],
'produces': ['application/xml'],
'consumes': ['application/x-www-form-urlencoded'],
'produces': ['application/json', 'application/xml'],
'externalDocs': {

@@ -69,4 +69,4 @@ 'description': 'Find out more about HAPI',

expect(response.result.basePath).to.equal('/base');
expect(response.result.consumes).to.deep.equal(['application/xml']);
expect(response.result.produces).to.deep.equal(['application/xml']);
expect(response.result.consumes).to.deep.equal(['application/x-www-form-urlencoded']);
expect(response.result.produces).to.deep.equal(['application/json', 'application/xml']);
expect(response.result.externalDocs).to.deep.equal(swaggerOptions.externalDocs);

@@ -73,0 +73,0 @@ done();

'use strict';
const Code = require('code');
const Joi = require('joi');
const Hoek = require('hoek');

@@ -15,7 +16,30 @@ const Lab = require('lab');

let routes = {
method: 'GET',
method: 'POST',
path: '/test',
handler: Helper.defaultHandler,
config: {
tags: ['api']
description: 'Add sum',
notes: ['Adds a sum to the data store'],
tags: ['api'],
validate: {
payload: {
a: Joi.number()
.required()
.description('the first number').default(10),
b: Joi.number()
.required()
.description('the second number'),
operator: Joi.string()
.required()
.default('+')
.valid(['+', '-', '/', '*'])
.description('the opertator i.e. + - / or *'),
equals: Joi.number()
.required()
.description('the result of the sum')
}
}
}

@@ -25,6 +49,24 @@ };

lab.test('notes', (done) => {
lab.test('summary and description', (done) => {
Helper.createServer({}, routes, (err, server) => {
server.inject({ method: 'GET', url: '/swagger.json' }, function (response) {
expect(err).to.equal(null);
//console.log(JSON.stringify(response.result));
expect(response.statusCode).to.equal(200);
expect(response.result.paths['/test'].post.summary).to.equal('Add sum');
expect(response.result.paths['/test'].post.description).to.equal('Adds a sum to the data store');
done();
});
});
});
lab.test('description as an array', (done) => {
let testRoutes = Hoek.clone(routes);
testRoutes.config.notes = ['single item'];
testRoutes.config.notes = ['note one', 'note two'];
Helper.createServer({}, testRoutes, (err, server) => {

@@ -37,3 +79,3 @@

expect(response.statusCode).to.equal(200);
expect(response.result.paths['/test'].get.description).to.equal('single item');
expect(response.result.paths['/test'].post.description).to.equal('note one<br/><br/>note two');
done();

@@ -45,6 +87,12 @@ });

lab.test('notes as an array', (done) => {
lab.test('route settting of consumes produces', (done) => {
let testRoutes = Hoek.clone(routes);
testRoutes.config.notes = ['note one', 'note two'];
testRoutes.config.plugins = {
'hapi-swagger': {
consumes: ['application/x-www-form-urlencoded'],
produces: ['application/json', 'application/xml']
}
};
Helper.createServer({}, testRoutes, (err, server) => {

@@ -55,5 +103,36 @@

expect(err).to.equal(null);
//console.log(JSON.stringify(response.result.paths['/test'].post.consumes));
expect(response.statusCode).to.equal(200);
expect(response.result.paths['/test'].post.consumes).to.deep.equal(['application/x-www-form-urlencoded']);
expect(response.result.paths['/test'].post.produces).to.deep.equal(['application/json', 'application/xml']);
done();
});
});
});
lab.test('override plug-in settting of consumes produces', (done) => {
let swaggerOptions = {
consumes: ['application/json'],
produces: ['application/json']
};
let testRoutes = Hoek.clone(routes);
testRoutes.config.plugins = {
'hapi-swagger': {
consumes: ['application/x-www-form-urlencoded'],
produces: ['application/json', 'application/xml']
}
};
Helper.createServer(swaggerOptions, testRoutes, (err, server) => {
server.inject({ method: 'GET', url: '/swagger.json' }, function (response) {
expect(err).to.equal(null);
//console.log(JSON.stringify(response.result));
expect(response.statusCode).to.equal(200);
expect(response.result.paths['/test'].get.description).to.equal('note one<br/><br/>note two');
expect(response.result.paths['/test'].post.consumes).to.deep.equal(['application/x-www-form-urlencoded']);
expect(response.result.paths['/test'].post.produces).to.deep.equal(['application/json', 'application/xml']);
done();

@@ -64,2 +143,107 @@ });

lab.test('auto "x-www-form-urlencoded" consumes with payloadType', (done) => {
let testRoutes = Hoek.clone(routes);
testRoutes.config.plugins = {
'hapi-swagger': {
payloadType: 'form'
}
};
Helper.createServer({}, testRoutes, (err, server) => {
server.inject({ method: 'GET', url: '/swagger.json' }, function (response) {
expect(err).to.equal(null);
//console.log(JSON.stringify(response.result));
expect(response.statusCode).to.equal(200);
expect(response.result.paths['/test'].post.consumes).to.deep.equal(['application/x-www-form-urlencoded']);
done();
});
});
});
lab.test('auto "multipart/form-data" consumes with { swaggerType: "file" }', (done) => {
let testRoutes = Hoek.clone(routes);
testRoutes.config.validate = {
payload: {
file: Joi.any()
.meta({ swaggerType: 'file' })
.description('json file')
}
},
Helper.createServer({}, testRoutes, (err, server) => {
server.inject({ method: 'GET', url: '/swagger.json' }, function (response) {
expect(err).to.equal(null);
//console.log(JSON.stringify(response.result));
expect(response.statusCode).to.equal(200);
expect(response.result.paths['/test'].post.consumes).to.deep.equal(['multipart/form-data']);
done();
});
});
});
lab.test('auto "multipart/form-data" do not add two', (done) => {
let testRoutes = Hoek.clone(routes);
testRoutes.config.validate = {
payload: {
file: Joi.any()
.meta({ swaggerType: 'file' })
.description('json file')
}
},
testRoutes.config.plugins = {
'hapi-swagger': {
consumes: ['multipart/form-data']
}
};
Helper.createServer({}, testRoutes, (err, server) => {
server.inject({ method: 'GET', url: '/swagger.json' }, function (response) {
expect(err).to.equal(null);
//console.log(JSON.stringify(response.result));
expect(response.statusCode).to.equal(200);
expect(response.result.paths['/test'].post.consumes).to.deep.equal(['multipart/form-data']);
done();
});
});
});
lab.test('payloadType form', (done) => {
let testRoutes = Hoek.clone(routes);
testRoutes.config.plugins = {
'hapi-swagger': {
payloadType: 'form'
}
};
Helper.createServer({}, testRoutes, (err, server) => {
server.inject({ method: 'GET', url: '/swagger.json' }, function (response) {
expect(err).to.equal(null);
//console.log(JSON.stringify(response.result));
expect(response.statusCode).to.equal(200);
expect(response.result.paths['/test'].post.consumes).to.deep.equal(['application/x-www-form-urlencoded']);
done();
});
});
});
});

@@ -320,7 +320,2 @@ 'use strict';

/* not yet 'x',

@@ -341,3 +336,2 @@ any.invalid(value)

lab.test('toParameters', (done) => {

@@ -344,0 +338,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc