From 32f0f5e37dcdb61029346cde40907c2ef0dcc874 Mon Sep 17 00:00:00 2001 From: Samuel Reed Date: Sat, 26 Jul 2014 10:53:08 -0500 Subject: [PATCH 1/5] Allow passing a custom protocol. This allows swagger definitions to work properly when the API is behind an SSL terminator. --- README.md | 10 ++++++++++ lib/swagger.js | 11 ++++++----- test/swagger.test.js | 12 ++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f962d0f..882e104 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,16 @@ Options are passed to `explorer(app, options)`. > to a path different than '/api', e.g. with > `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** > Sets a path within your application for overriding Swagger UI files. diff --git a/lib/swagger.js b/lib/swagger.js index c886ac3..5b20608 100644 --- a/lib/swagger.js +++ b/lib/swagger.js @@ -24,7 +24,7 @@ var routeHelper = require('./route-helper'); * @param {Object} opts Options. */ function Swagger(loopbackApplication, swaggerApp, opts) { - opts = _defaults({}, opts, { + _defaults(opts || {}, { swaggerVersion: '1.2', basePath: loopbackApplication.get('restApiRoot') || '/api', resourcePath: 'resources', @@ -48,7 +48,7 @@ function Swagger(loopbackApplication, swaggerApp, opts) { // Add the getter for this doc. 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. @@ -73,7 +73,7 @@ function Swagger(loopbackApplication, swaggerApp, opts) { * resources available on the system, and where to find more * information about them. */ - addRoute(swaggerApp, opts.resourcePath, resourceDoc); + addRoute(swaggerApp, opts.resourcePath, resourceDoc, opts); } /** @@ -82,7 +82,7 @@ function Swagger(loopbackApplication, swaggerApp, opts) { * @param {String} uri Path from which to serve the doc. * @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 initialPath = doc.basePath || ''; @@ -100,7 +100,8 @@ function addRoute(app, uri, doc) { if (hasBasePath) { var headers = req.headers; var host = headers.Host || headers.host; - doc.basePath = req.protocol + '://' + host + initialPath; + doc.basePath = (opts.protocol || req.protocol) + '://' + + host + initialPath; } res.send(200, doc); }); diff --git a/test/swagger.test.js b/test/swagger.test.js index 2fd6bd2..1cd0a5b 100644 --- a/test/swagger.test.js +++ b/test/swagger.test.js @@ -69,6 +69,18 @@ describe('swagger definition', function() { 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() { From f7734fe5b399c41cd9f0a95fb3ce6e95967e0d33 Mon Sep 17 00:00:00 2001 From: Ritchie Martori Date: Thu, 31 Jul 2014 15:52:52 -0700 Subject: [PATCH 2/5] Add required swagger 1.2 items property for property type array --- lib/model-helper.js | 16 +++++++++++----- test/model-helper.test.js | 9 ++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/model-helper.js b/lib/model-helper.js index d612489..e36ce6f 100644 --- a/lib/model-helper.js +++ b/lib/model-helper.js @@ -104,12 +104,18 @@ var modelHelper = module.exports = { out.type = modelHelper.getPropType(out.type); 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) { - var arrayProp = prop.type[0]; - if (!arrayProp.type) arrayProp = {type: arrayProp}; - out.items = modelHelper.LDLPropToSwaggerDataType(arrayProp); + if (arrayItem) { + if(typeof arrayItem === 'object') { + out.items = modelHelper.LDLPropToSwaggerDataType(arrayItem); + } 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') { out.type = 'string'; diff --git a/test/model-helper.test.js b/test/model-helper.test.js index d196a26..0676767 100644 --- a/test/model-helper.test.js +++ b/test/model-helper.test.js @@ -86,7 +86,10 @@ describe('model-helper', function() { 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() { @@ -96,7 +99,7 @@ describe('model-helper', function() { array: [undefined] }); 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() { @@ -104,7 +107,7 @@ describe('model-helper', function() { array: 'array' }); var prop = def.properties.array; - expect(prop).to.eql({ type: 'array' }); + expect(prop).to.eql({ type: 'array', items: { type: 'any' } }); }); }); }); From df459ffc8bbdc5ea0423b50131184434bfce9bad Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Thu, 31 Jul 2014 16:47:47 -0700 Subject: [PATCH 3/5] Fix the default opts --- lib/swagger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/swagger.js b/lib/swagger.js index 5d76098..da4102c 100644 --- a/lib/swagger.js +++ b/lib/swagger.js @@ -24,7 +24,7 @@ var routeHelper = require('./route-helper'); * @param {Object} opts Options. */ function Swagger(loopbackApplication, swaggerApp, opts) { - _defaults(opts || {}, { + opts = _defaults(opts || {}, { swaggerVersion: '1.2', basePath: loopbackApplication.get('restApiRoot') || '/api', resourcePath: 'resources', From 0aa476a6824611542e7fa8a1f477688ee73b6864 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Sun, 3 Aug 2014 21:48:16 -0700 Subject: [PATCH 4/5] Set up default consumes/produces media types See: https://github.com/strongloop/loopback/issues/432 https://github.com/wordnik/swagger-js/issues/107 --- lib/class-helper.js | 2 ++ lib/swagger.js | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/class-helper.js b/lib/class-helper.js index de3a0a7..333b5ea 100644 --- a/lib/class-helper.js +++ b/lib/class-helper.js @@ -28,6 +28,8 @@ var classHelper = module.exports = { basePath: opts.basePath, resourcePath: urlJoin('/', opts.resourcePath), apis: [], + consumes: aClass.http.consumes || opts.consumes, + produces: aClass.http.produces || opts.produces, models: modelHelper.generateModelDefinition(aClass.ctor, {}) }; }, diff --git a/lib/swagger.js b/lib/swagger.js index da4102c..d517303 100644 --- a/lib/swagger.js +++ b/lib/swagger.js @@ -7,12 +7,10 @@ module.exports = Swagger; /** * Module dependencies. */ -var debug = require('debug')('loopback:explorer:swagger'); var path = require('path'); var urlJoin = require('./url-join'); var _defaults = require('lodash.defaults'); var classHelper = require('./class-helper'); -var modelHelper = require('./model-helper'); var routeHelper = require('./route-helper'); /** @@ -28,6 +26,9 @@ function Swagger(loopbackApplication, swaggerApp, opts) { swaggerVersion: '1.2', basePath: loopbackApplication.get('restApiRoot') || '/api', resourcePath: 'resources', + // Default consumes/produces to application/json + consumes: ['application/json'], + produces: ['application/json'], version: getVersion() }); From db0ca06a4de4a8c72858ddebaa4674fb12cad4f6 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Mon, 4 Aug 2014 09:08:49 -0700 Subject: [PATCH 5/5] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 05eb9fb..62ccc93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-explorer", - "version": "1.2.6", + "version": "1.2.7", "description": "Browse and test your LoopBack app's APIs", "main": "index.js", "scripts": {