Merge pull request #104 from strongloop/feature/refactor-as-component
[SEMVER-MAJOR] Rework the module to a loopback component
This commit is contained in:
commit
75ea3f928a
40
README.md
40
README.md
|
@ -16,13 +16,43 @@ var Product = loopback.Model.extend('product');
|
||||||
Product.attachTo(loopback.memory());
|
Product.attachTo(loopback.memory());
|
||||||
app.model(Product);
|
app.model(Product);
|
||||||
|
|
||||||
app.use('/explorer', explorer(app, {basePath: '/api'}));
|
|
||||||
app.use('/api', loopback.rest());
|
app.use('/api', loopback.rest());
|
||||||
|
|
||||||
|
// Register explorer using component-centric API:
|
||||||
|
explorer(app, { basePath: '/api', mountPath: '/explorer' });
|
||||||
|
// Alternatively, register as a middleware:
|
||||||
|
app.use('/explorer', explorer.routes(app, { basePath: '/api' }));
|
||||||
|
|
||||||
console.log("Explorer mounted at localhost:" + port + "/explorer");
|
console.log("Explorer mounted at localhost:" + port + "/explorer");
|
||||||
|
|
||||||
app.listen(port);
|
app.listen(port);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Upgrading from v1.x
|
||||||
|
|
||||||
|
To upgrade your application using loopback-explorer version 1.x, just replace
|
||||||
|
`explorer()` with `explorer.routes()` in your server script:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var explorer = require('loopback-explorer');
|
||||||
|
|
||||||
|
// v1.x - does not work anymore
|
||||||
|
app.use('/explorer', explorer(app, options);
|
||||||
|
// v2.x
|
||||||
|
app.use('/explorer', explorer.routes(app, options));
|
||||||
|
```
|
||||||
|
|
||||||
|
In applications scaffolded by `slc loopback`, the idiomatic way is to register
|
||||||
|
loopback-explorer via `component-config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"loopback-explorer": {
|
||||||
|
"mountPath": "/explorer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Advanced Usage
|
## Advanced Usage
|
||||||
|
|
||||||
Many aspects of the explorer are configurable.
|
Many aspects of the explorer are configurable.
|
||||||
|
@ -32,7 +62,7 @@ See [options](#options) for a description of these options:
|
||||||
```js
|
```js
|
||||||
// Mount middleware before calling `explorer()` to add custom headers, auth, etc.
|
// Mount middleware before calling `explorer()` to add custom headers, auth, etc.
|
||||||
app.use('/explorer', loopback.basicAuth('user', 'password'));
|
app.use('/explorer', loopback.basicAuth('user', 'password'));
|
||||||
app.use('/explorer', explorer(app, {
|
explorer(app, {
|
||||||
basePath: '/custom-api-root',
|
basePath: '/custom-api-root',
|
||||||
uiDirs: [
|
uiDirs: [
|
||||||
path.resolve(__dirname, 'public'),
|
path.resolve(__dirname, 'public'),
|
||||||
|
@ -60,6 +90,12 @@ 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());
|
||||||
|
|
||||||
|
`mountPath`: **String**
|
||||||
|
|
||||||
|
> Default: `/explorer`
|
||||||
|
|
||||||
|
> Set the path where to mount the explorer component.
|
||||||
|
|
||||||
`protocol`: **String**
|
`protocol`: **String**
|
||||||
|
|
||||||
> Default: `null`
|
> Default: `null`
|
||||||
|
|
37
index.js
37
index.js
|
@ -6,35 +6,46 @@ var url = require('url');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var urlJoin = require('./lib/url-join');
|
var urlJoin = require('./lib/url-join');
|
||||||
var _defaults = require('lodash').defaults;
|
var _defaults = require('lodash').defaults;
|
||||||
var express = require('express');
|
|
||||||
var swagger = require('./lib/swagger');
|
var swagger = require('./lib/swagger');
|
||||||
var SWAGGER_UI_ROOT = require('strong-swagger-ui').dist;
|
var SWAGGER_UI_ROOT = require('strong-swagger-ui').dist;
|
||||||
var STATIC_ROOT = path.join(__dirname, 'public');
|
var STATIC_ROOT = path.join(__dirname, 'public');
|
||||||
|
|
||||||
module.exports = explorer;
|
module.exports = explorer;
|
||||||
|
explorer.routes = routes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example usage:
|
* Example usage:
|
||||||
*
|
*
|
||||||
* var explorer = require('loopback-explorer');
|
* var explorer = require('loopback-explorer');
|
||||||
* app.use('/explorer', explorer(app, options));
|
* explorer(app, options);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function explorer(loopbackApplication, options) {
|
function explorer(loopbackApplication, options) {
|
||||||
|
var mountPath = options.mountPath || '/explorer';
|
||||||
|
loopbackApplication.use(mountPath, routes(loopbackApplication, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
function routes(loopbackApplication, options) {
|
||||||
|
var loopback = loopbackApplication.loopback;
|
||||||
|
var loopbackMajor = loopback && loopback.version &&
|
||||||
|
loopback.version.split('.')[0] || 1;
|
||||||
|
|
||||||
|
if (loopbackMajor < 2) {
|
||||||
|
throw new Error('loopback-explorer requires loopback 2.0 or newer');
|
||||||
|
}
|
||||||
|
|
||||||
options = _defaults({}, options, {
|
options = _defaults({}, options, {
|
||||||
resourcePath: 'resources',
|
resourcePath: 'resources',
|
||||||
apiInfo: loopbackApplication.get('apiInfo') || {}
|
apiInfo: loopbackApplication.get('apiInfo') || {}
|
||||||
});
|
});
|
||||||
|
|
||||||
var app = express();
|
var router = new loopback.Router();
|
||||||
|
|
||||||
swagger(loopbackApplication, app, options);
|
swagger(loopbackApplication, router, options);
|
||||||
|
|
||||||
app.disable('x-powered-by');
|
|
||||||
|
|
||||||
// config.json is loaded by swagger-ui. The server should respond
|
// config.json is loaded by swagger-ui. The server should respond
|
||||||
// with the relative URI of the resource doc.
|
// with the relative URI of the resource doc.
|
||||||
app.get('/config.json', function(req, res) {
|
router.get('/config.json', function(req, res) {
|
||||||
// Get the path we're mounted at. It's best to get this from the referer
|
// Get the path we're mounted at. It's best to get this from the referer
|
||||||
// in case we're proxied at a deep path.
|
// in case we're proxied at a deep path.
|
||||||
var source = url.parse(req.headers.referer || '').pathname;
|
var source = url.parse(req.headers.referer || '').pathname;
|
||||||
|
@ -53,10 +64,10 @@ function explorer(loopbackApplication, options) {
|
||||||
// to worry about constantly pulling in JS updates.
|
// to worry about constantly pulling in JS updates.
|
||||||
if (options.uiDirs) {
|
if (options.uiDirs) {
|
||||||
if (typeof options.uiDirs === 'string') {
|
if (typeof options.uiDirs === 'string') {
|
||||||
app.use(express.static(options.uiDirs));
|
router.use(loopback.static(options.uiDirs));
|
||||||
} else if (Array.isArray(options.uiDirs)) {
|
} else if (Array.isArray(options.uiDirs)) {
|
||||||
options.uiDirs.forEach(function(dir) {
|
options.uiDirs.forEach(function(dir) {
|
||||||
app.use(express.static(dir));
|
router.use(loopback.static(dir));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,14 +75,14 @@ function explorer(loopbackApplication, options) {
|
||||||
if (options.swaggerDistRoot) {
|
if (options.swaggerDistRoot) {
|
||||||
console.warn('loopback-explorer: `swaggerDistRoot` is deprecated,' +
|
console.warn('loopback-explorer: `swaggerDistRoot` is deprecated,' +
|
||||||
' use `uiDirs` instead');
|
' use `uiDirs` instead');
|
||||||
app.use(express.static(options.swaggerDistRoot));
|
router.use(loopback.static(options.swaggerDistRoot));
|
||||||
}
|
}
|
||||||
|
|
||||||
// File in node_modules are overridden by a few customizations
|
// File in node_modules are overridden by a few customizations
|
||||||
app.use(express.static(STATIC_ROOT));
|
router.use(loopback.static(STATIC_ROOT));
|
||||||
|
|
||||||
// Swagger UI distribution
|
// Swagger UI distribution
|
||||||
app.use(express.static(SWAGGER_UI_ROOT));
|
router.use(loopback.static(SWAGGER_UI_ROOT));
|
||||||
|
|
||||||
return app;
|
return router;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cors": "^2.7.1",
|
"cors": "^2.7.1",
|
||||||
"debug": "^2.2.0",
|
"debug": "^2.2.0",
|
||||||
"express": "4.x",
|
|
||||||
"lodash": "^3.10.0",
|
"lodash": "^3.10.0",
|
||||||
"strong-swagger-ui": "^20.0.2"
|
"strong-swagger-ui": "^20.0.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,9 +106,9 @@ describe('explorer', function() {
|
||||||
var app;
|
var app;
|
||||||
beforeEach(function setupExplorerWithUiDirs() {
|
beforeEach(function setupExplorerWithUiDirs() {
|
||||||
app = loopback();
|
app = loopback();
|
||||||
app.use('/explorer', explorer(app, {
|
explorer(app, {
|
||||||
uiDirs: [ path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui') ]
|
uiDirs: [ path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui') ]
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('overrides swagger-ui files', function(done) {
|
it('overrides swagger-ui files', function(done) {
|
||||||
|
@ -128,6 +128,27 @@ describe('explorer', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('explorer.routes API', function() {
|
||||||
|
var app;
|
||||||
|
beforeEach(function() {
|
||||||
|
app = loopback();
|
||||||
|
var Product = loopback.PersistedModel.extend('product');
|
||||||
|
Product.attachTo(loopback.memory());
|
||||||
|
app.model(Product);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates explorer routes', function(done) {
|
||||||
|
app.use('/explorer', explorer.routes(app));
|
||||||
|
app.use(app.get('restApiRoot') || '/', loopback.rest());
|
||||||
|
|
||||||
|
request(app)
|
||||||
|
.get('/explorer/config.json')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.end(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when specifying custom static file root directories', function() {
|
describe('when specifying custom static file root directories', function() {
|
||||||
var app;
|
var app;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
@ -135,9 +156,9 @@ describe('explorer', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow `uiDirs` to be defined as an Array', function(done) {
|
it('should allow `uiDirs` to be defined as an Array', function(done) {
|
||||||
app.use('/explorer', explorer(app, {
|
explorer(app, {
|
||||||
uiDirs: [ path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui') ]
|
uiDirs: [ path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui') ]
|
||||||
}));
|
});
|
||||||
|
|
||||||
request(app).get('/explorer/')
|
request(app).get('/explorer/')
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
@ -147,9 +168,9 @@ describe('explorer', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow `uiDirs` to be defined as an String', function(done) {
|
it('should allow `uiDirs` to be defined as an String', function(done) {
|
||||||
app.use('/explorer', explorer(app, {
|
explorer(app, {
|
||||||
uiDirs: path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui')
|
uiDirs: path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui')
|
||||||
}));
|
});
|
||||||
|
|
||||||
request(app).get('/explorer/')
|
request(app).get('/explorer/')
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
@ -172,7 +193,7 @@ describe('explorer', function() {
|
||||||
Product.attachTo(loopback.memory());
|
Product.attachTo(loopback.memory());
|
||||||
app.model(Product);
|
app.model(Product);
|
||||||
|
|
||||||
app.use(explorerBase || '/explorer', explorer(app));
|
explorer(app, { mountPath: explorerBase });
|
||||||
app.use(app.get('restApiRoot') || '/', loopback.rest());
|
app.use(app.get('restApiRoot') || '/', loopback.rest());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
var urlJoin = require('../lib/url-join');
|
var urlJoin = require('../lib/url-join');
|
||||||
var loopback = require('loopback');
|
var loopback = require('loopback');
|
||||||
var express = require('express');
|
|
||||||
var swagger = require('../lib/swagger');
|
var swagger = require('../lib/swagger');
|
||||||
|
|
||||||
var request = require('supertest');
|
var request = require('supertest');
|
||||||
|
@ -387,7 +386,7 @@ describe('swagger definition', function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function mountExplorer(app, options) {
|
function mountExplorer(app, options) {
|
||||||
var swaggerApp = express();
|
var swaggerApp = loopback();
|
||||||
swagger(app, swaggerApp, options);
|
swagger(app, swaggerApp, options);
|
||||||
app.use(app.get('explorerRoot') || '/explorer', swaggerApp);
|
app.use(app.get('explorerRoot') || '/explorer', swaggerApp);
|
||||||
return app;
|
return app;
|
||||||
|
|
Loading…
Reference in New Issue