Use express routes instead of modifying remoting.
This completes the migration of swagger processing from strong-remoting into loopback-explorer. Added additional usage instructions to README and additional testing. This commit introduces a change into where resource descriptors are hosted. They are no longer hosted under /swagger, but instead under the same path as the Explorer, wherever that may be. Generally, the resource listing will be available at /explorer/resources, and api listings under /explorer/resources/{modelName}.
This commit is contained in:
parent
19c3fe3870
commit
70dddef296
66
README.md
66
README.md
|
@ -16,28 +16,82 @@ var Product = loopback.Model.extend('product');
|
|||
Product.attachTo(loopback.memory());
|
||||
app.model(Product);
|
||||
|
||||
app.use('/explorer', explorer(app, {} /* options */));
|
||||
app.use(loopback.rest());
|
||||
app.use('/explorer', explorer(app, {basePath: '/api'}));
|
||||
app.use('/api', loopback.rest());
|
||||
console.log("Explorer mounted at localhost:" + port + "/explorer");
|
||||
|
||||
app.listen(port);
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
Many aspects of the explorer are configurable.
|
||||
|
||||
See [options](#options) for a description of these options:
|
||||
|
||||
```js
|
||||
app.use('/explorer', explorer(app, {
|
||||
basePath: '/custom-api-root',
|
||||
preMiddleware: [
|
||||
// You can add as many items to this middleware chain as you like
|
||||
loopback.basicAuth(bitmex.settings.basicAuth.user, bitmex.settings.basicAuth.password)
|
||||
],
|
||||
swaggerDistRoot: '/swagger',
|
||||
apiInfo: {
|
||||
'title': 'My API',
|
||||
'description': 'Explorer example app.'
|
||||
},
|
||||
resourcePath: 'swaggerResources',
|
||||
version: '0.1-unreleasable'
|
||||
}));
|
||||
app.use('/custom-api-root', loopback.rest());
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
Options are passed to `explorer(app, options)`.
|
||||
|
||||
`basePath`: **String**
|
||||
|
||||
> Set the base path for swagger resources.
|
||||
> Default: `app.get('restAPIRoot')` or `/swagger/resources`.
|
||||
> Default: `app.get('restAPIRoot')` or `'/api'`.
|
||||
|
||||
> Sets the API's base path. This must be set if you are mounting your api
|
||||
> to a path different than '/api', e.g. with
|
||||
> `loopback.use('/custom-api-root', loopback.rest());
|
||||
|
||||
|
||||
`swaggerDistRoot`: **String**
|
||||
|
||||
> Set a path within your application for overriding Swagger UI files.
|
||||
> Sets a path 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.
|
||||
> 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
|
||||
> [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
|
||||
> [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.
|
||||
|
||||
`version`: **String**
|
||||
|
||||
> Default: Read from package.json
|
||||
|
||||
> Sets your API version. If not present, will read from your app's package.json.
|
||||
|
||||
`preMiddleware`: **Array<Function>|Function**
|
||||
|
||||
> Middleware to run before any explorer routes, including static routes.
|
||||
|
||||
> Useful for setting HTTP Auth, modifying the `Host` header, and so on.
|
||||
|
|
|
@ -11,8 +11,9 @@ var Product = loopback.Model.extend('product', {
|
|||
Product.attachTo(loopback.memory());
|
||||
app.model(Product);
|
||||
|
||||
app.use('/explorer', explorer(app));
|
||||
app.use(loopback.rest());
|
||||
console.log("Explorer mounted at localhost:" + port + "/explorer");
|
||||
var apiPath = '/api';
|
||||
app.use('/explorer', explorer(app, {basePath: apiPath}));
|
||||
app.use(apiPath, loopback.rest());
|
||||
console.log('Explorer mounted at localhost:' + port + '/explorer');
|
||||
|
||||
app.listen(port);
|
||||
|
|
35
index.js
35
index.js
|
@ -9,7 +9,8 @@ var loopback = require('loopback');
|
|||
var express = requireLoopbackDependency('express');
|
||||
var swagger = require('./lib/swagger');
|
||||
var fs = require('fs');
|
||||
var SWAGGER_UI_ROOT = path.join(__dirname, 'node_modules', 'swagger-ui', 'dist');
|
||||
var SWAGGER_UI_ROOT = path.join(__dirname, 'node_modules',
|
||||
'swagger-ui', 'dist');
|
||||
var STATIC_ROOT = path.join(__dirname, 'public');
|
||||
|
||||
module.exports = explorer;
|
||||
|
@ -23,27 +24,38 @@ module.exports = explorer;
|
|||
|
||||
function explorer(loopbackApplication, options) {
|
||||
options = _defaults({}, options, {
|
||||
basePath: loopbackApplication.get('restApiRoot') || '',
|
||||
name: 'swagger',
|
||||
resourcePath: 'resources',
|
||||
apiInfo: loopbackApplication.get('apiInfo') || {}
|
||||
apiInfo: loopbackApplication.get('apiInfo') || {},
|
||||
preMiddleware: []
|
||||
});
|
||||
|
||||
swagger(loopbackApplication.remotes(), options);
|
||||
|
||||
var app = express();
|
||||
|
||||
swagger(loopbackApplication, app, options);
|
||||
|
||||
// Allow the user to attach middleware that will run before any
|
||||
// explorer routes, e.g. for access control.
|
||||
if (typeof options.preMiddleware === 'function' ||
|
||||
(Array.isArray(options.preMiddleware) && options.preMiddleware.length)) {
|
||||
app.use(options.preMiddleware);
|
||||
}
|
||||
|
||||
app.disable('x-powered-by');
|
||||
|
||||
// config.json is loaded by swagger-ui. The server should respond
|
||||
// with the relative URI of the resource doc.
|
||||
app.get('/config.json', function(req, res) {
|
||||
var resourcePath = req.originalUrl.replace(/\/config.json(\?.*)?$/,
|
||||
path.join('/', options.resourcePath));
|
||||
res.send({
|
||||
url: path.join(options.basePath || '/', options.name, options.resourcePath)
|
||||
url: resourcePath
|
||||
});
|
||||
});
|
||||
// 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 to worry about constantly pulling in
|
||||
// JS updates.
|
||||
|
||||
// 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
|
||||
// to worry about constantly pulling in JS updates.
|
||||
if (options.swaggerDistRoot) {
|
||||
app.use(loopback.static(options.swaggerDistRoot));
|
||||
}
|
||||
|
@ -51,6 +63,7 @@ function explorer(loopbackApplication, options) {
|
|||
app.use(loopback.static(STATIC_ROOT));
|
||||
// Swagger UI distribution
|
||||
app.use(loopback.static(SWAGGER_UI_ROOT));
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@ var path = require('path');
|
|||
* Export the classHelper singleton.
|
||||
*/
|
||||
var classHelper = module.exports = {
|
||||
// See below.
|
||||
addDynamicBasePathGetter: addDynamicBasePathGetter,
|
||||
/**
|
||||
* Given a remoting class, generate an API doc.
|
||||
* See https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#52-api-declaration
|
||||
|
@ -47,52 +45,3 @@ var classHelper = module.exports = {
|
|||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* There's a few forces at play that require this "hack". The Swagger spec
|
||||
* requires a `basePath` to be set at various points in the API/Resource
|
||||
* descriptions. However, we can't guarantee this path is either reachable or
|
||||
* desirable if it's set as a part of the options.
|
||||
*
|
||||
* The simplest way around this is to reflect the value of the `Host` HTTP
|
||||
* header as the `basePath`. Because we pre-build the Swagger data, we don't
|
||||
* know that header at the time the data is built. Hence, the getter function.
|
||||
* We can use a `before` hook to pluck the `Host`, then the getter kicks in to
|
||||
* return that path as the `basePath` during JSON serialization.
|
||||
*
|
||||
* @param {SharedClassCollection} remotes The Collection to register a `before`
|
||||
* hook on.
|
||||
* @param {String} path The full path of the route to register
|
||||
* a `before` hook on.
|
||||
* @param {Object} obj The Object to install the `basePath`
|
||||
* getter on.
|
||||
*/
|
||||
function addDynamicBasePathGetter(remotes, path, obj) {
|
||||
var initialPath = obj.basePath || '';
|
||||
var basePath = String(obj.basePath) || '';
|
||||
|
||||
if (!/^https?:\/\//.test(basePath)) {
|
||||
remotes.before(path, function (ctx, next) {
|
||||
var headers = ctx.req.headers;
|
||||
var host = headers.Host || headers.host;
|
||||
|
||||
basePath = ctx.req.protocol + '://' + host + initialPath;
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
return setter(obj);
|
||||
|
||||
function getter() {
|
||||
return basePath;
|
||||
}
|
||||
|
||||
function setter(obj) {
|
||||
return Object.defineProperty(obj, 'basePath', {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: getter
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ module.exports = Swagger;
|
|||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var Remoting = require('strong-remoting');
|
||||
var debug = require('debug')('loopback-explorer:swagger');
|
||||
var path = require('path');
|
||||
var _defaults = require('lodash.defaults');
|
||||
|
@ -17,38 +16,38 @@ var routeHelper = require('./route-helper');
|
|||
|
||||
/**
|
||||
* Create a remotable Swagger module for plugging into `RemoteObjects`.
|
||||
*
|
||||
* @param {Application} loopbackApplication Host loopback application.
|
||||
* @param {Application} swaggerApp Swagger application used for hosting
|
||||
* these files.
|
||||
* @param {Object} opts Options.
|
||||
*/
|
||||
function Swagger(remotes, opts) {
|
||||
function Swagger(loopbackApplication, swaggerApp, opts) {
|
||||
opts = _defaults({}, opts, {
|
||||
name: 'swagger',
|
||||
swaggerVersion: '1.2',
|
||||
basePath: loopbackApplication.get('restApiRoot') || '/api',
|
||||
resourcePath: 'resources',
|
||||
version: getVersion(),
|
||||
basePath: '/'
|
||||
version: getVersion()
|
||||
});
|
||||
|
||||
// We need a temporary REST adapter to discover our available routes.
|
||||
var remotes = loopbackApplication.remotes();
|
||||
var adapter = remotes.handler('rest').adapter;
|
||||
var routes = adapter.allRoutes();
|
||||
var classes = remotes.classes();
|
||||
|
||||
// Create a new Remoting instance to host the swagger docs.
|
||||
var extension = {};
|
||||
var helper = Remoting.extend(extension);
|
||||
|
||||
// These are the docs we will be sending from the /swagger endpoints.
|
||||
var resourceDoc = generateResourceDoc(opts);
|
||||
var apiDocs = {};
|
||||
|
||||
// A class is an endpoint root; e.g. /users, /products, and so on.
|
||||
classes.forEach(function (aClass) {
|
||||
apiDocs[aClass.name] = classHelper.generateAPIDoc(aClass, opts);
|
||||
var doc = apiDocs[aClass.name] = classHelper.generateAPIDoc(aClass, opts);
|
||||
resourceDoc.apis.push(classHelper.generateResourceDocAPIEntry(aClass));
|
||||
|
||||
// Add the getter for this doc.
|
||||
var docPath = path.join(opts.resourcePath, aClass.http.path);
|
||||
addRoute(helper, apiDocs[aClass.name], docPath);
|
||||
classHelper.addDynamicBasePathGetter(remotes, opts.name + '.' + docPath, apiDocs[aClass.name]);
|
||||
addRoute(swaggerApp, docPath, doc);
|
||||
});
|
||||
|
||||
// A route is an endpoint, such as /users/findOne.
|
||||
|
@ -69,31 +68,41 @@ function Swagger(remotes, opts) {
|
|||
});
|
||||
|
||||
/**
|
||||
* The topmost Swagger resource is a description of all (non-Swagger) resources
|
||||
* available on the system, and where to find more information about them.
|
||||
* The topmost Swagger resource is a description of all (non-Swagger)
|
||||
* resources available on the system, and where to find more
|
||||
* information about them.
|
||||
*/
|
||||
addRoute(helper, resourceDoc, opts.resourcePath);
|
||||
|
||||
// Bind all the above routes to the endpoint at /#{name}.
|
||||
remotes.exports[opts.name] = extension;
|
||||
|
||||
return extension;
|
||||
addRoute(swaggerApp, opts.resourcePath, resourceDoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a route to this remoting extension.
|
||||
* @param {Remote} helper Remoting extension.
|
||||
* @param {Object} doc Doc to serve.
|
||||
* @param {String} path Path from which to serve the doc.
|
||||
* @param {Application} app Express application.
|
||||
* @param {String} uri Path from which to serve the doc.
|
||||
* @param {Object} doc Doc to serve.
|
||||
*/
|
||||
function addRoute(helper, doc, path) {
|
||||
helper.method(getDoc, {
|
||||
path: path,
|
||||
returns: { type: 'object', root: true }
|
||||
function addRoute(app, uri, doc) {
|
||||
|
||||
var hasBasePath = Object.keys(doc).indexOf('basePath') !== -1;
|
||||
var initialPath = doc.basePath || '';
|
||||
|
||||
app.get(path.join('/', uri), function(req, res) {
|
||||
|
||||
// There's a few forces at play that require this "hack". The Swagger spec
|
||||
// requires a `basePath` to be set in the API descriptions. However, we
|
||||
// can't guarantee this path is either reachable or desirable if it's set
|
||||
// as a part of the options.
|
||||
//
|
||||
// The simplest way around this is to reflect the value of the `Host` HTTP
|
||||
// header as the `basePath`. Because we pre-build the Swagger data, we don't
|
||||
// know that header at the time the data is built.
|
||||
if (hasBasePath) {
|
||||
var headers = req.headers;
|
||||
var host = headers.Host || headers.host;
|
||||
doc.basePath = req.protocol + '://' + host + initialPath;
|
||||
}
|
||||
res.send(200, doc);
|
||||
});
|
||||
function getDoc(callback) {
|
||||
callback(null, doc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
"mocha": "~1.14.0",
|
||||
"supertest": "~0.8.1",
|
||||
"chai": "~1.8.1",
|
||||
"strong-remoting": "^2.0.0-beta4"
|
||||
"express": "3.x"
|
||||
},
|
||||
"license": {
|
||||
"name": "Dual MIT/StrongLoop",
|
||||
|
|
|
@ -38,24 +38,24 @@ describe('explorer', function() {
|
|||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body).to
|
||||
.have.property('url', '/swagger/resources');
|
||||
.have.property('url', '/explorer/resources');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with custom baseUrl', function() {
|
||||
beforeEach(givenLoopBackAppWithExplorer('/api'));
|
||||
describe('with custom explorer base', function() {
|
||||
beforeEach(givenLoopBackAppWithExplorer('/swagger'));
|
||||
|
||||
it('should serve correct swagger-ui config', function(done) {
|
||||
request(this.app)
|
||||
.get('/explorer/config.json')
|
||||
.get('/swagger/config.json')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body).to
|
||||
.have.property('url', '/api/swagger/resources');
|
||||
.have.property('url', '/swagger/resources');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -73,36 +73,26 @@ describe('explorer', function() {
|
|||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body).to
|
||||
.have.property('url', '/rest-api-root/swagger/resources');
|
||||
.have.property('url', '/explorer/resources');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function givenLoopBackAppWithExplorer(restUrlBase) {
|
||||
function givenLoopBackAppWithExplorer(explorerBase) {
|
||||
return function(done) {
|
||||
var app = this.app = loopback();
|
||||
configureRestApiAndExplorer(app, restUrlBase);
|
||||
configureRestApiAndExplorer(app, explorerBase);
|
||||
done();
|
||||
};
|
||||
}
|
||||
|
||||
function configureRestApiAndExplorer(app, restUrlBase) {
|
||||
function configureRestApiAndExplorer(app, explorerBase) {
|
||||
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());
|
||||
}
|
||||
app.use(explorerBase || '/explorer', explorer(app));
|
||||
app.use(app.get('restApiRoot') || '/', loopback.rest());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -22,26 +22,19 @@
|
|||
var url = require('url');
|
||||
var path = require('path');
|
||||
var loopback = require('loopback');
|
||||
|
||||
var RemoteObjects = require('strong-remoting');
|
||||
var express = require('express');
|
||||
var swagger = require('../lib/swagger.js');
|
||||
|
||||
var request = require('supertest');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
describe('swagger definition', function() {
|
||||
var app;
|
||||
|
||||
beforeEach(function() {
|
||||
app = createLoopbackAppWithModel();
|
||||
});
|
||||
|
||||
describe('basePath', function() {
|
||||
// No basepath on resource doc in 1.2
|
||||
it('no longer exists on resource doc', function(done) {
|
||||
swagger(app.remotes());
|
||||
var app = mountSwagger();
|
||||
|
||||
var getReq = getSwaggerResources();
|
||||
var getReq = getSwaggerResources(app);
|
||||
getReq.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body.basePath).to.equal(undefined);
|
||||
|
@ -49,21 +42,21 @@ describe('swagger definition', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('is "http://{host}/" by default', function(done) {
|
||||
swagger(app.remotes());
|
||||
it('is "http://{host}/api" by default', function(done) {
|
||||
var app = mountSwagger();
|
||||
|
||||
var getReq = getAPIDeclaration('products');
|
||||
var getReq = getAPIDeclaration(app, 'products');
|
||||
getReq.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body.basePath).to.equal(url.resolve(getReq.url, '/'));
|
||||
expect(res.body.basePath).to.equal(url.resolve(getReq.url, '/api'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('is "http://{host}/{basePath}" when basePath is a path', function(done){
|
||||
swagger(app.remotes(), { basePath: '/api-root'});
|
||||
var app = mountSwagger({ basePath: '/api-root'});
|
||||
|
||||
var getReq = getAPIDeclaration('products');
|
||||
var getReq = getAPIDeclaration(app, 'products');
|
||||
getReq.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
var apiRoot = url.resolve(getReq.url, '/api-root');
|
||||
|
@ -72,15 +65,26 @@ describe('swagger definition', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('is custom URL when basePath is a http(s) URL', function(done) {
|
||||
var apiUrl = 'http://custom-api-url/';
|
||||
it('infers API basePath from app', function(done){
|
||||
var app = mountSwagger({}, {apiRoot: '/custom-api-root'});
|
||||
|
||||
swagger(app.remotes(), { basePath: apiUrl });
|
||||
|
||||
var getReq = getAPIDeclaration('products');
|
||||
var getReq = getAPIDeclaration(app, 'products');
|
||||
getReq.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body.basePath).to.equal(apiUrl);
|
||||
var apiRoot = url.resolve(getReq.url, '/custom-api-root');
|
||||
expect(res.body.basePath).to.equal(apiRoot);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('is reachable when explorer mounting location is changed', function(done){
|
||||
var explorerRoot = '/erforscher';
|
||||
var app = mountSwagger({}, {explorerRoot: explorerRoot});
|
||||
|
||||
var getReq = getSwaggerResources(app, explorerRoot, 'products');
|
||||
getReq.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body.basePath).to.be.a('string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -88,8 +92,12 @@ describe('swagger definition', function() {
|
|||
|
||||
describe('Model definition attributes', function() {
|
||||
it('Properly defines basic attributes', function(done) {
|
||||
var extension = swagger(app.remotes(), {});
|
||||
getModelFromRemoting(extension, 'product', function(data) {
|
||||
var app = mountSwagger();
|
||||
|
||||
var getReq = getAPIDeclaration(app, 'products');
|
||||
getReq.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
var data = res.body.models.product;
|
||||
expect(data.id).to.equal('product');
|
||||
expect(data.required.sort()).to.eql(['id', 'aNum', 'foo'].sort());
|
||||
expect(data.properties.foo.type).to.equal('string');
|
||||
|
@ -105,19 +113,28 @@ describe('swagger definition', function() {
|
|||
});
|
||||
});
|
||||
|
||||
function getSwaggerResources(restPath, classPath) {
|
||||
function getSwaggerResources(app, restPath, classPath) {
|
||||
return request(app)
|
||||
.get(path.join(restPath || '', '/swagger/resources', classPath || ''))
|
||||
.get(path.join(restPath || '/explorer', '/resources', classPath || ''))
|
||||
.set('Accept', 'application/json')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200);
|
||||
}
|
||||
|
||||
function getAPIDeclaration(className) {
|
||||
return getSwaggerResources('', path.join('/', className));
|
||||
function getAPIDeclaration(app, className) {
|
||||
return getSwaggerResources(app, '', path.join('/', className));
|
||||
}
|
||||
|
||||
function createLoopbackAppWithModel() {
|
||||
function mountSwagger(options, addlOptions) {
|
||||
addlOptions = addlOptions || {};
|
||||
var app = createLoopbackAppWithModel(addlOptions.apiRoot);
|
||||
var swaggerApp = express();
|
||||
swagger(app, swaggerApp, options);
|
||||
app.use(addlOptions.explorerRoot || '/explorer', swaggerApp);
|
||||
return app;
|
||||
}
|
||||
|
||||
function createLoopbackAppWithModel(apiRoot) {
|
||||
var app = loopback();
|
||||
|
||||
var Product = loopback.Model.extend('product', {
|
||||
|
@ -128,14 +145,10 @@ describe('swagger definition', function() {
|
|||
Product.attachTo(loopback.memory());
|
||||
app.model(Product);
|
||||
|
||||
app.use(loopback.rest());
|
||||
// Simulate a restApiRoot set in config
|
||||
app.set('restApiRoot', apiRoot || '/api');
|
||||
app.use(app.get('restApiRoot'), loopback.rest());
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
function getModelFromRemoting(extension, modelName, cb) {
|
||||
extension['resources/' + modelName + 's'](function(err, data) {
|
||||
cb(data.models[modelName]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue