From a4179e454aaeed182de394284afca7cd86f3d175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 22 Oct 2014 11:10:15 +0200 Subject: [PATCH 1/3] swagger: honour X-Forwarded-Proto header Improve the algorithm building `baseUrl` to honour `X-Forwarded-Proto` header when it is present. --- lib/swagger.js | 4 ++-- test/swagger.test.js | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/swagger.js b/lib/swagger.js index 32843b7..5da84ae 100644 --- a/lib/swagger.js +++ b/lib/swagger.js @@ -166,9 +166,9 @@ function addRoute(app, uri, doc, opts) { if (hasBasePath) { var headers = req.headers; // NOTE header names (keys) are always all-lowercase + var proto = headers['x-forwarded-proto'] || opts.protocol || req.protocol; var host = headers['x-forwarded-host'] || headers.host; - doc.basePath = (opts.protocol || req.protocol) + '://' + - host + initialPath; + doc.basePath = proto + '://' + host + initialPath; } res.status(200).send(doc); }); diff --git a/test/swagger.test.js b/test/swagger.test.js index 9a79082..f70c9b0 100644 --- a/test/swagger.test.js +++ b/test/swagger.test.js @@ -93,6 +93,18 @@ describe('swagger definition', function() { done(); }); }); + + it('respects X-Forwarded-Proto header (behind a proxy)', function(done) { + var app = givenAppWithSwagger(); + getAPIDeclaration(app, 'products') + .set('X-Forwarded-Proto', 'https') + .end(function(err, res) { + if (err) return done(err); + var baseUrl = url.parse(res.body.basePath); + expect(baseUrl.protocol).to.equal('https:'); + done(); + }); + }); }); describe('Model definition attributes', function() { From 2ec096a278448d01b682dfd2f3963fdc0c46e482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 22 Oct 2014 10:55:25 +0200 Subject: [PATCH 2/3] Add an option `uiDirs` The `uiDirs` option allows users to provide their own set of directories with UI files, e.g. to provide a custom swagger-ui fork and a custom set of style/font overrides: explorer(app, { uiDirs: [ path.resolve(__dirname, 'public'), path.resolve(__dirname, 'node_modules', 'swagger-ui') ] }); The existing option `swaggerDistRoot` is deprecated now. --- README.md | 21 ++++++++------ index.js | 16 +++++++++-- test/explorer.test.js | 29 +++++++++++++++++++- test/fixtures/dummy-swagger-ui/index.html | 1 + test/fixtures/dummy-swagger-ui/swagger-ui.js | 1 + 5 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 test/fixtures/dummy-swagger-ui/index.html create mode 100644 test/fixtures/dummy-swagger-ui/swagger-ui.js diff --git a/README.md b/README.md index 882e104..9ef49eb 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ app.listen(port); ## Advanced Usage -Many aspects of the explorer are configurable. +Many aspects of the explorer are configurable. See [options](#options) for a description of these options: @@ -34,7 +34,10 @@ See [options](#options) for a description of these options: app.use('/explorer', loopback.basicAuth('user', 'password')); app.use('/explorer', explorer(app, { basePath: '/custom-api-root', - swaggerDistRoot: '/swagger', + uiDirs: [ + path.resolve(__dirname, 'public'), + path.resolve(__dirname, 'node_modules', 'swagger-ui') + ] apiInfo: { 'title': 'My API', 'description': 'Explorer example app.' @@ -67,27 +70,27 @@ Options are passed to `explorer(app, options)`. > and thus needs to report its endpoints as `https`, even though incoming traffic is auto-detected > as `http`. -`swaggerDistRoot`: **String** +`uiDirs`: **Array of Strings** -> Sets a path within your application for overriding Swagger UI files. +> Sets a list of paths within your application for overriding Swagger UI files. -> If present, will search `swaggerDistRoot` first when attempting to load Swagger UI, allowing -> you to pick and choose overrides to the interface. Use this to style your explorer or -> add additional functionality. +> If present, will search `uiDirs` first when attempting to load Swagger UI, +> allowing you to pick and choose overrides to the interface. Use this to +> style your explorer or add additional functionality. > See [index.html](public/index.html), where you may want to begin your overrides. > The rest of the UI is provided by [Swagger UI](https://github.com/wordnik/swagger-ui). `apiInfo`: **Object** -> Additional information about your API. See the +> Additional information about your API. See the > [spec](https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#513-info-object). `resourcePath`: **String** > Default: `'resources'` -> Sets a different path for the +> Sets a different path for the > [resource listing](https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#51-resource-listing). > You generally shouldn't have to change this. diff --git a/index.js b/index.js index 6c5e003..e34a778 100644 --- a/index.js +++ b/index.js @@ -47,15 +47,25 @@ function explorer(loopbackApplication, options) { }); }); - // Allow specifying a static file root for swagger files. Any files in - // that folder will override those in the swagger-ui distribution. - // In this way one could e.g. make changes to index.html without having + // Allow specifying a static file roots for swagger files. Any files in + // these folders will override those in the swagger-ui distribution. + // In this way one could e.g. make changes to index.html without having // to worry about constantly pulling in JS updates. + if (options.uiDirs) { + options.uiDirs.forEach(function(dir) { + app.use(express.static(dir)); + }); + } + if (options.swaggerDistRoot) { + console.warn('loopback-explorer: `swaggerDistRoot` is deprecated,' + + ' use `uiDirs` instead'); app.use(express.static(options.swaggerDistRoot)); } + // File in node_modules are overridden by a few customizations app.use(express.static(STATIC_ROOT)); + // Swagger UI distribution app.use(express.static(SWAGGER_UI_ROOT)); diff --git a/test/explorer.test.js b/test/explorer.test.js index e53c4d9..ce900aa 100644 --- a/test/explorer.test.js +++ b/test/explorer.test.js @@ -2,6 +2,7 @@ var loopback = require('loopback'); var explorer = require('../'); var request = require('supertest'); var assert = require('assert'); +var path = require('path'); var expect = require('chai').expect; describe('explorer', function() { @@ -24,7 +25,7 @@ describe('explorer', function() { .end(function(err, res) { if (err) throw err; - assert(!!~res.text.indexOf('StrongLoop API Explorer'), + assert(!!~res.text.indexOf('StrongLoop API Explorer'), 'text does not contain expected string'); done(); }); @@ -79,6 +80,32 @@ describe('explorer', function() { }); }); + describe('with custom front-end files', function() { + var app; + beforeEach(function setupExplorerWithUiDirs() { + app = loopback(); + app.use('/explorer', explorer(app, { + uiDirs: [ path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui') ] + })); + }); + + it('overrides swagger-ui files', function(done) { + request(app).get('/explorer/swagger-ui.js') + .expect(200) + // expect the content of `dummy-swagger-ui/swagger-ui.js` + .expect('/* custom swagger-ui file */\n') + .end(done); + }); + + it('overrides strongloop overrides', function(done) { + request(app).get('/explorer/') + .expect(200) + // expect the content of `dummy-swagger-ui/index.html` + .expect('custom index.html\n') + .end(done); + }); + }); + function givenLoopBackAppWithExplorer(explorerBase) { return function(done) { var app = this.app = loopback(); diff --git a/test/fixtures/dummy-swagger-ui/index.html b/test/fixtures/dummy-swagger-ui/index.html new file mode 100644 index 0000000..f6c3a1f --- /dev/null +++ b/test/fixtures/dummy-swagger-ui/index.html @@ -0,0 +1 @@ +custom index.html diff --git a/test/fixtures/dummy-swagger-ui/swagger-ui.js b/test/fixtures/dummy-swagger-ui/swagger-ui.js new file mode 100644 index 0000000..55f593f --- /dev/null +++ b/test/fixtures/dummy-swagger-ui/swagger-ui.js @@ -0,0 +1 @@ +/* custom swagger-ui file */ From ee2d0d4ddb627ff7af25e950ba76ef9304024428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Fri, 24 Oct 2014 19:31:30 +0200 Subject: [PATCH 3/3] 1.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d550307..6b7771e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-explorer", - "version": "1.4.0", + "version": "1.5.0", "description": "Browse and test your LoopBack app's APIs", "main": "index.js", "scripts": {