Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand All @@ -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) {
Expand All @@ -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;
}

Expand Down
77 changes: 61 additions & 16 deletions test/explorer.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var format = require('util').format;
var loopback = require('loopback');
var explorer = require('../');
var request = require('supertest');
Expand Down Expand Up @@ -41,7 +42,7 @@ describe('explorer', function() {
done();
});
});
})
});

describe('with custom baseUrl', function() {
beforeEach(givenLoopBackAppWithExplorer('/api'));
Expand All @@ -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());
}
}
});