Merge remote-tracking branch 'upstream/master'
* upstream/master: Bump version Set up default consumes/produces media types Fix the default opts Add required swagger 1.2 items property for property type array Allow passing a custom protocol. Conflicts: lib/swagger.js
This commit is contained in:
commit
28d293b6f9
10
README.md
10
README.md
|
@ -57,6 +57,16 @@ Options are passed to `explorer(app, options)`.
|
||||||
> to a path different than '/api', e.g. with
|
> to a path different than '/api', e.g. with
|
||||||
> `loopback.use('/custom-api-root', loopback.rest());
|
> `loopback.use('/custom-api-root', loopback.rest());
|
||||||
|
|
||||||
|
`protocol`: **String**
|
||||||
|
|
||||||
|
> Default: `null`
|
||||||
|
|
||||||
|
> A hard override for the outgoing protocol (`http` or `https`) that is designated in Swagger
|
||||||
|
> resource documents. By default, `loopback-explorer` will write the protocol that was used to retrieve
|
||||||
|
> the doc. This option is useful if, for instance, your API sits behind an SSL terminator
|
||||||
|
> and thus needs to report its endpoints as `https`, even though incoming traffic is auto-detected
|
||||||
|
> as `http`.
|
||||||
|
|
||||||
`swaggerDistRoot`: **String**
|
`swaggerDistRoot`: **String**
|
||||||
|
|
||||||
> Sets a path within your application for overriding Swagger UI files.
|
> Sets a path within your application for overriding Swagger UI files.
|
||||||
|
|
|
@ -28,6 +28,8 @@ var classHelper = module.exports = {
|
||||||
basePath: opts.basePath,
|
basePath: opts.basePath,
|
||||||
resourcePath: urlJoin('/', opts.resourcePath),
|
resourcePath: urlJoin('/', opts.resourcePath),
|
||||||
apis: [],
|
apis: [],
|
||||||
|
consumes: aClass.http.consumes || opts.consumes,
|
||||||
|
produces: aClass.http.produces || opts.produces,
|
||||||
models: modelHelper.generateModelDefinition(aClass.ctor, {})
|
models: modelHelper.generateModelDefinition(aClass.ctor, {})
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -104,12 +104,18 @@ var modelHelper = module.exports = {
|
||||||
out.type = modelHelper.getPropType(out.type);
|
out.type = modelHelper.getPropType(out.type);
|
||||||
|
|
||||||
if (out.type === 'array') {
|
if (out.type === 'array') {
|
||||||
var hasItemType = typeof prop.type !== 'string' && prop.type[0];
|
var hasItemType = Array.isArray(prop.type) && prop.type.length;
|
||||||
|
var arrayItem = hasItemType && prop.type[0];
|
||||||
|
|
||||||
if (hasItemType) {
|
if (arrayItem) {
|
||||||
var arrayProp = prop.type[0];
|
if(typeof arrayItem === 'object') {
|
||||||
if (!arrayProp.type) arrayProp = {type: arrayProp};
|
out.items = modelHelper.LDLPropToSwaggerDataType(arrayItem);
|
||||||
out.items = modelHelper.LDLPropToSwaggerDataType(arrayProp);
|
} else {
|
||||||
|
out.items = { type: modelHelper.getPropType(arrayItem) };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// NOTE: `any` is not a supported type in swagger 1.2
|
||||||
|
out.items = { type: 'any' };
|
||||||
}
|
}
|
||||||
} else if (out.type === 'date') {
|
} else if (out.type === 'date') {
|
||||||
out.type = 'string';
|
out.type = 'string';
|
||||||
|
|
|
@ -7,12 +7,10 @@ module.exports = Swagger;
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
var debug = require('debug')('loopback:explorer:swagger');
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var urlJoin = require('./url-join');
|
var urlJoin = require('./url-join');
|
||||||
var _defaults = require('lodash.defaults');
|
var _defaults = require('lodash.defaults');
|
||||||
var classHelper = require('./class-helper');
|
var classHelper = require('./class-helper');
|
||||||
var modelHelper = require('./model-helper');
|
|
||||||
var routeHelper = require('./route-helper');
|
var routeHelper = require('./route-helper');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,10 +22,13 @@ var routeHelper = require('./route-helper');
|
||||||
* @param {Object} opts Options.
|
* @param {Object} opts Options.
|
||||||
*/
|
*/
|
||||||
function Swagger(loopbackApplication, swaggerApp, opts) {
|
function Swagger(loopbackApplication, swaggerApp, opts) {
|
||||||
opts = _defaults({}, opts, {
|
opts = _defaults(opts || {}, {
|
||||||
swaggerVersion: '1.2',
|
swaggerVersion: '1.2',
|
||||||
basePath: loopbackApplication.get('restApiRoot') || '/api',
|
basePath: loopbackApplication.get('restApiRoot') || '/api',
|
||||||
resourcePath: 'resources',
|
resourcePath: 'resources',
|
||||||
|
// Default consumes/produces to application/json
|
||||||
|
consumes: ['application/json'],
|
||||||
|
produces: ['application/json'],
|
||||||
version: getVersion()
|
version: getVersion()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ function Swagger(loopbackApplication, swaggerApp, opts) {
|
||||||
|
|
||||||
// Add the getter for this doc.
|
// Add the getter for this doc.
|
||||||
var docPath = urlJoin(opts.resourcePath, aClass.http.path);
|
var docPath = urlJoin(opts.resourcePath, aClass.http.path);
|
||||||
addRoute(swaggerApp, docPath, doc);
|
addRoute(swaggerApp, docPath, doc, opts);
|
||||||
});
|
});
|
||||||
|
|
||||||
// A route is an endpoint, such as /users/findOne.
|
// A route is an endpoint, such as /users/findOne.
|
||||||
|
@ -73,7 +74,7 @@ function Swagger(loopbackApplication, swaggerApp, opts) {
|
||||||
* resources available on the system, and where to find more
|
* resources available on the system, and where to find more
|
||||||
* information about them.
|
* information about them.
|
||||||
*/
|
*/
|
||||||
addRoute(swaggerApp, opts.resourcePath, resourceDoc);
|
addRoute(swaggerApp, opts.resourcePath, resourceDoc, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,7 +83,7 @@ function Swagger(loopbackApplication, swaggerApp, opts) {
|
||||||
* @param {String} uri Path from which to serve the doc.
|
* @param {String} uri Path from which to serve the doc.
|
||||||
* @param {Object} doc Doc to serve.
|
* @param {Object} doc Doc to serve.
|
||||||
*/
|
*/
|
||||||
function addRoute(app, uri, doc) {
|
function addRoute(app, uri, doc, opts) {
|
||||||
|
|
||||||
var hasBasePath = Object.keys(doc).indexOf('basePath') !== -1;
|
var hasBasePath = Object.keys(doc).indexOf('basePath') !== -1;
|
||||||
var initialPath = doc.basePath || '';
|
var initialPath = doc.basePath || '';
|
||||||
|
@ -100,7 +101,7 @@ function addRoute(app, uri, doc) {
|
||||||
if (hasBasePath) {
|
if (hasBasePath) {
|
||||||
var headers = req.headers;
|
var headers = req.headers;
|
||||||
var host = headers.Host || headers.host;
|
var host = headers.Host || headers.host;
|
||||||
var protocol = headers['x-forwarded-proto'] || headers['X-Forwarded-Proto'] || ctx.req.protocol
|
var protocol = headers['x-forwarded-proto'] || headers['X-Forwarded-Proto'] || opts.protocol || req.protocol
|
||||||
doc.basePath = protocol + '://' + host + initialPath;
|
doc.basePath = protocol + '://' + host + initialPath;
|
||||||
}
|
}
|
||||||
res.status(200).send(doc);
|
res.status(200).send(doc);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "loopback-explorer",
|
"name": "loopback-explorer",
|
||||||
"version": "1.2.6",
|
"version": "1.2.7",
|
||||||
"description": "Browse and test your LoopBack app's APIs",
|
"description": "Browse and test your LoopBack app's APIs",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -86,7 +86,10 @@ describe('model-helper', function() {
|
||||||
array: []
|
array: []
|
||||||
});
|
});
|
||||||
var prop = def.properties.array;
|
var prop = def.properties.array;
|
||||||
expect(prop).to.eql({ type: 'array' });
|
expect(prop).to.eql({
|
||||||
|
type: 'array',
|
||||||
|
items: { type: 'any' }
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('converts [undefined] type', function() {
|
it('converts [undefined] type', function() {
|
||||||
|
@ -96,7 +99,7 @@ describe('model-helper', function() {
|
||||||
array: [undefined]
|
array: [undefined]
|
||||||
});
|
});
|
||||||
var prop = def.properties.array;
|
var prop = def.properties.array;
|
||||||
expect(prop).to.eql({ type: 'array' });
|
expect(prop).to.eql({ type: 'array', items: { type: 'any' } });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('converts "array" type', function() {
|
it('converts "array" type', function() {
|
||||||
|
@ -104,7 +107,7 @@ describe('model-helper', function() {
|
||||||
array: 'array'
|
array: 'array'
|
||||||
});
|
});
|
||||||
var prop = def.properties.array;
|
var prop = def.properties.array;
|
||||||
expect(prop).to.eql({ type: 'array' });
|
expect(prop).to.eql({ type: 'array', items: { type: 'any' } });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -69,6 +69,18 @@ describe('swagger definition', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('respects a hardcoded protocol (behind SSL terminator)', function(done){
|
||||||
|
var app = mountSwagger({protocol: 'https'});
|
||||||
|
|
||||||
|
var getReq = getAPIDeclaration(app, 'products');
|
||||||
|
getReq.end(function(err, res) {
|
||||||
|
if (err) return done(err);
|
||||||
|
var parsed = url.parse(res.body.basePath);
|
||||||
|
expect(parsed.protocol).to.equal('https:');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Model definition attributes', function() {
|
describe('Model definition attributes', function() {
|
||||||
|
|
Loading…
Reference in New Issue