diff --git a/index.js b/index.js index 5965e89..b5c4589 100644 --- a/index.js +++ b/index.js @@ -2,8 +2,8 @@ * Adds dynamically-updated docs as /explorer */ var path = require('path'); +var extend = require('util')._extend; var loopback = require('loopback'); -var swagger = requireLoopbackDependency('strong-remoting/ext/swagger'); var express = requireLoopbackDependency('express'); var STATIC_ROOT = path.join(__dirname, 'public'); @@ -13,13 +13,14 @@ module.exports = explorer; * Example usage: * * var explorer = require('loopback-explorer'); - * app.use('/explorer', explorer(app)); + * app.use('/explorer', explorer(app, options)); */ function explorer(loopbackApplication, options) { - var options = options || {}; - var remotes = loopbackApplication.remotes(); - swagger(remotes, options); + options = extend({}, options); + options.basePath = options.basePath || loopbackApplication.get('restApiRoot'); + + loopbackApplication.docs(options); var app = express(); app.get('/config.json', function(req, res) { @@ -28,6 +29,16 @@ function explorer(loopbackApplication, options) { }); }); app.use(loopback.static(STATIC_ROOT)); + + loopbackApplication.once('start', function() { + var baseUrl = 'http://' + this.get('host') + ':' + this.get('port'); + // `app.route` is filled by `expressApp.use(route, app)`, i.e. + // loopbackApplication.use('/explorer', explorer(loopbackApplication)) + // sets `app.route = '/explorer'` + var explorerPath = app.route; + console.log('Browse your REST API at %s%s', baseUrl, explorerPath); + }); + return app; } diff --git a/test/explorer.test.js b/test/explorer.test.js index a208544..e88dadb 100644 --- a/test/explorer.test.js +++ b/test/explorer.test.js @@ -1,3 +1,4 @@ +var format = require('util').format; var loopback = require('loopback'); var explorer = require('../'); var request = require('supertest'); @@ -41,7 +42,7 @@ describe('explorer', function() { done(); }); }); - }) + }); describe('with custom baseUrl', function() { beforeEach(givenLoopBackAppWithExplorer('/api')); @@ -60,25 +61,69 @@ describe('explorer', function() { }); }); + describe('with custom app.restApiRoot', function() { + it('should serve correct swagger-ui config', function(done) { + var app = loopback(); + app.set('restApiRoot', '/rest-api-root'); + configureRestApiAndExplorer(app); + + request(app) + .get('/explorer/config.json') + .expect(200) + .end(function(err, res) { + if (err) return done(err); + expect(res.body).to + .have.property('discoveryUrl', '/rest-api-root/swagger/resources'); + done(); + }); + }); + }); + + it('reports correct explorer URL on app start', function() { + var messages = []; + console._log = console.log; + console.log = function() { + messages.push(format.apply(null, Array.prototype.slice.call(arguments))); + }; + + var app = loopback(); + app.set('host', 'custom-host'); + app.set('port', 12345); + app.use('/custom-api', loopback.rest()); + app.use('/custom-explorer', explorer(app, { basePath: '/custom-root' })); + app.emit('start'); + + console.log = console._log; + delete console._log; + + expect(messages).to.have.length(1); + expect(messages[0]).to.contain('http://custom-host:12345/custom-explorer'); + }); + function givenLoopBackAppWithExplorer(restUrlBase) { return function(done) { var app = this.app = loopback(); - var Product = loopback.Model.extend('product'); - Product.attachTo(loopback.memory()); - app.model(Product); - - if (restUrlBase) { - app.use(restUrlBase, loopback.rest()); - app.use('/explorer', explorer(app, { basePath: restUrlBase })); - } else { - // LoopBack REST adapter owns the whole URL space and does not - // let other middleware handle same URLs. - // It's possible to circumvent this measure by installing - // the explorer middleware before the REST middleware. - app.use('/explorer', explorer(app)); - app.use(loopback.rest()); - } + configureRestApiAndExplorer(app, restUrlBase); done(); + }; + } + + function configureRestApiAndExplorer(app, restUrlBase) { + var Product = loopback.Model.extend('product'); + Product.attachTo(loopback.memory()); + app.model(Product); + + if (restUrlBase) { + app.use(restUrlBase, loopback.rest()); + app.use('/explorer', explorer(app, { basePath: restUrlBase })); + } else { + // LoopBack REST adapter owns the whole URL space and does not + // let other middleware handle same URLs. + // It's possible to circumvent this measure by installing + // the explorer middleware before the REST middleware. + // This way we can acess `/explorer` even when REST is mounted at `/` + app.use('/explorer', explorer(app)); + app.use(app.get('restApiRoot') || '/', loopback.rest()); } } });