Merge branch 'master' of github.com:strongloop/loopback-explorer into feature/remove-express-dep
This commit is contained in:
commit
5377503c8c
|
@ -0,0 +1,313 @@
|
|||
2015-02-23, Version 1.7.1
|
||||
=========================
|
||||
|
||||
* Remove unused external font "Droid Sans". (Miroslav Bajtoš)
|
||||
|
||||
|
||||
2015-02-17, Version 1.7.0
|
||||
=========================
|
||||
|
||||
* Made API doc of class use the http.path of the class if available, or the name of the class as a fallback (gandrianakis)
|
||||
|
||||
|
||||
2015-01-09, Version 1.6.4
|
||||
=========================
|
||||
|
||||
* Prevent double slash in the resource URLs (Miroslav Bajtoš)
|
||||
|
||||
* Allow `uiDirs` to be defined as a String (Simon Ho)
|
||||
|
||||
* Save accessToken in localStorage. Fixes #47 (Samuel Reed)
|
||||
|
||||
|
||||
2015-01-06, Version 1.6.3
|
||||
=========================
|
||||
|
||||
* Fix bad CLA URL in CONTRIBUTING.md (Ryan Graham)
|
||||
|
||||
* Add X-UA-Compatible tag (Nick Van Dyck)
|
||||
|
||||
|
||||
2014-12-12, Version 1.6.2
|
||||
=========================
|
||||
|
||||
* Move 200 response to `type` on the operation object. See #75. (Samuel Reed)
|
||||
|
||||
|
||||
2014-12-08, Version 1.6.1
|
||||
=========================
|
||||
|
||||
* Use full lodash instead of lodash components (Ryan Graham)
|
||||
|
||||
|
||||
2014-12-02, Version 1.6.0
|
||||
=========================
|
||||
|
||||
* Remove model name from nickname, swagger spec understands op context. (Samuel Reed)
|
||||
|
||||
|
||||
2014-11-29, Version 1.5.2
|
||||
=========================
|
||||
|
||||
* model-helper: ignore unknown property types (Miroslav Bajtoš)
|
||||
|
||||
|
||||
2014-10-24, Version 1.5.1
|
||||
=========================
|
||||
|
||||
|
||||
|
||||
2014-10-24, Version 1.5.0
|
||||
=========================
|
||||
|
||||
* Add an option `uiDirs` (Miroslav Bajtoš)
|
||||
|
||||
* swagger: honour X-Forwarded-Proto header (Miroslav Bajtoš)
|
||||
|
||||
|
||||
2014-10-21, Version 1.4.0
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Add integration tests for included models (Miroslav Bajtoš)
|
||||
|
||||
* route-helper: add `responseMessages` (Miroslav Bajtoš)
|
||||
|
||||
* model-helper: support anonymous object types (Miroslav Bajtoš)
|
||||
|
||||
* swagger: include models from accepts/returns args (Miroslav Bajtoš)
|
||||
|
||||
* loopbackStyles: improve spacing in small window (Miroslav Bajtoš)
|
||||
|
||||
* swagger: Deprecate `opts.swaggerVersion` (Miroslav Bajtoš)
|
||||
|
||||
* swagger: use X-Forwarded-Host for basePath (Miroslav Bajtoš)
|
||||
|
||||
* example: use PersistedModel instead of Model (Miroslav Bajtoš)
|
||||
|
||||
* models: include model's `description` (Miroslav Bajtoš)
|
||||
|
||||
* Refactor conversion of data types (Miroslav Bajtoš)
|
||||
|
||||
* Move `convertText` to `typeConverter` (Miroslav Bajtoš)
|
||||
|
||||
* Add support for `context` and `res` param types (Krishna Raman)
|
||||
|
||||
* package: update devDependencies (Miroslav Bajtoš)
|
||||
|
||||
* gitignore: add .idea, *.tgz, *.iml (Miroslav Bajtoš)
|
||||
|
||||
* Support multi-line array `description` and `notes` (Miroslav Bajtoš)
|
||||
|
||||
* Use `1.0.0` as the default app version. (Miroslav Bajtoš)
|
||||
|
||||
* Extend `consumes` and `produces` metadata (Miroslav Bajtoš)
|
||||
|
||||
* route-helper: include `notes` and `deprecated` (Miroslav Bajtoš)
|
||||
|
||||
* Pull model description from ctor.settings first (Shelby Sanders)
|
||||
|
||||
|
||||
2014-10-08, Version 1.3.0
|
||||
=========================
|
||||
|
||||
* swagger: allow cross-origin requests (Miroslav Bajtoš)
|
||||
|
||||
* Sort endpoints by letter. (Samuel Reed)
|
||||
|
||||
* Add syntax highlighting styles & highlight threshold. (Samuel Reed)
|
||||
|
||||
* Add contribution guidelines (Ryan Graham)
|
||||
|
||||
|
||||
2014-09-22, Version 1.2.11
|
||||
==========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Fix how the array of models is iterated (Raymond Feng)
|
||||
|
||||
|
||||
2014-09-05, Version 1.2.10
|
||||
==========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Make sure nested/referenced models in array are mapped to swagger (Clark Wang)
|
||||
|
||||
* Make sure nested/referenced models are mapped to swagger (Raymond Feng)
|
||||
|
||||
|
||||
2014-08-15, Version 1.2.9
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Newest Swagger UI requires application/x-www-form-urlencoded. (Samuel Reed)
|
||||
|
||||
* Use `dist` property from swagger-ui package. (Samuel Reed)
|
||||
|
||||
* Fixed undefined modelClass when using polymorphic relations (Navid Nikpour)
|
||||
|
||||
|
||||
2014-08-08, Version 1.2.8
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Fix the type name for a property if model class is used (Raymond Feng)
|
||||
|
||||
|
||||
2014-08-04, Version 1.2.7
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Set up default consumes/produces media types (Raymond Feng)
|
||||
|
||||
* Fix the default opts (Raymond Feng)
|
||||
|
||||
* Add required swagger 1.2 items property for property type array (Ritchie Martori)
|
||||
|
||||
* Allow passing a custom protocol. (Samuel Reed)
|
||||
|
||||
|
||||
2014-07-29, Version 1.2.6
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* res.send deprecated - updated to res.status (Geoffroy)
|
||||
|
||||
* Remove hidden properties from definition. (Samuel Reed)
|
||||
|
||||
|
||||
2014-07-25, Version 1.2.5
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Ensure models from relations are included (Raymond Feng)
|
||||
|
||||
|
||||
2014-07-22, Version 1.2.4
|
||||
=========================
|
||||
|
||||
* model-helper: handle arrays with undefined items (Miroslav Bajtoš)
|
||||
|
||||
|
||||
2014-07-22, Version 1.2.3
|
||||
=========================
|
||||
|
||||
* model-helper: handle array types with no item type (Miroslav Bajtoš)
|
||||
|
||||
|
||||
2014-07-20, Version 1.2.2
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Properly convert complex return types. (Samuel Reed)
|
||||
|
||||
|
||||
2014-07-18, Version 1.2.1
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* Fix up loopback.rest() model definition hack. (Samuel Reed)
|
||||
|
||||
|
||||
2014-07-14, Version 1.2.0
|
||||
=========================
|
||||
|
||||
* Bump version and update deps (Raymond Feng)
|
||||
|
||||
* s/accessToken/access_token in authorization key name (Samuel Reed)
|
||||
|
||||
* Fix resources if the explorer is at a deep path. (Samuel Reed)
|
||||
|
||||
* Fix debug namespace, express version. (Samuel Reed)
|
||||
|
||||
* Remove forgotten TODO. (Samuel Reed)
|
||||
|
||||
* Simplify `accepts` and `returns` hacks. (Samuel Reed)
|
||||
|
||||
* More consise type tests (Samuel Reed)
|
||||
|
||||
* Remove preMiddleware. (Samuel Reed)
|
||||
|
||||
* Remove swagger.test.js license (Samuel Reed)
|
||||
|
||||
* Remove peerDependencies, use express directly. (Samuel Reed)
|
||||
|
||||
* Add url-join so path.join() doesn't break windows (Samuel Reed)
|
||||
|
||||
* Rename translateKeys to translateDataTypeKeys. (Samuel Reed)
|
||||
|
||||
* Refactor route-helper & add tests. (Samuel Reed)
|
||||
|
||||
* LDL to Swagger fixes & extensions. (Samuel Reed)
|
||||
|
||||
* Use express routes instead of modifying remoting. (Samuel Reed)
|
||||
|
||||
* Fix missing strong-remoting devDependency. (Samuel Reed)
|
||||
|
||||
* Restore existing styles. (Samuel Reed)
|
||||
|
||||
* Allow easy setting of accessToken in explorer UI. (Samuel Reed)
|
||||
|
||||
* Refactor key translations between LDL & Swagger. (Samuel Reed)
|
||||
|
||||
* Refactoring swagger 1.2 rework. (Samuel Reed)
|
||||
|
||||
* Make sure body parameter is shown. (Raymond Feng)
|
||||
|
||||
* Some swagger 1.2 migration cleanup. (Samuel Reed)
|
||||
|
||||
* Fix api resource path and type ref to models. (Raymond Feng)
|
||||
|
||||
* Swagger 1.2 compatability. Moved strong-remoting/ext/swagger to this module. (Samuel Reed)
|
||||
|
||||
* Load swagger ui from `swagger-ui` package instead. (Samuel Reed)
|
||||
|
||||
|
||||
2014-05-28, Version 1.1.1
|
||||
=========================
|
||||
|
||||
* package.json: add support for loopback 2.x (Miroslav Bajtoš)
|
||||
|
||||
* Make sure X-Powered-By header is disabled (Alex Pica)
|
||||
|
||||
* Fix license url (Raymond Feng)
|
||||
|
||||
* Update to dual MIT/StrongLoop license (Raymond Feng)
|
||||
|
||||
|
||||
2014-01-14, Version 1.1.0
|
||||
=========================
|
||||
|
||||
* Bump up loopback min version to 1.5 (Miroslav Bajtoš)
|
||||
|
||||
* Use `app.get('restApiRoot')` as default basePath (Miroslav Bajtoš)
|
||||
|
||||
* Replace strong-remoting ext/swagger with app.docs (Miroslav Bajtoš)
|
||||
|
||||
|
||||
2014-01-13, Version 1.0.2
|
||||
=========================
|
||||
|
||||
* Bump version (Raymond Feng)
|
||||
|
||||
* README: mount REST at /api in the sample code (Miroslav Bajtos)
|
||||
|
||||
* Reorder middleware to fix unit-test failures. (Miroslav Bajtos)
|
||||
|
||||
* Fix loading of loopback dependencies. (Miroslav Bajtos)
|
||||
|
||||
|
||||
2013-12-04, Version 1.0.1
|
||||
=========================
|
||||
|
||||
* First release!
|
|
@ -14,7 +14,7 @@ Contributing to `loopback-explorer` is easy. In a few simple steps:
|
|||
* Adhere to code style outlined in the [Google C++ Style Guide][] and
|
||||
[Google Javascript Style Guide][].
|
||||
|
||||
* Sign the [Contributor License Agreement](https://cla.strongloop.com/strongloop/loopback-explorer)
|
||||
* Sign the [Contributor License Agreement](https://cla.strongloop.com/agreements/strongloop/loopback-explorer)
|
||||
|
||||
* Submit a pull request through Github.
|
||||
|
||||
|
|
15
README.md
15
README.md
|
@ -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,13 +70,13 @@ 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).
|
||||
|
|
20
index.js
20
index.js
|
@ -5,7 +5,7 @@
|
|||
var url = require('url');
|
||||
var path = require('path');
|
||||
var urlJoin = require('./lib/url-join');
|
||||
var _defaults = require('lodash.defaults');
|
||||
var _defaults = require('lodash').defaults;
|
||||
var swagger = require('./lib/swagger');
|
||||
var SWAGGER_UI_ROOT = require('swagger-ui').dist;
|
||||
var STATIC_ROOT = path.join(__dirname, 'public');
|
||||
|
@ -46,15 +46,29 @@ 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.
|
||||
// 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) {
|
||||
if (typeof options.uiDirs === 'string') {
|
||||
app.use(loopback.static(options.uiDirs));
|
||||
} else if (Array.isArray(options.uiDirs)) {
|
||||
options.uiDirs.forEach(function(dir) {
|
||||
app.use(loopback.static(dir));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (options.swaggerDistRoot) {
|
||||
app.use(loopback.static(options.swaggerDistRoot));
|
||||
console.warn('loopback-explorer: `swaggerDistRoot` is deprecated,' +
|
||||
' use `uiDirs` instead');
|
||||
}
|
||||
|
||||
// File in node_modules are overridden by a few customizations
|
||||
app.use(loopback.static(STATIC_ROOT));
|
||||
|
||||
// Swagger UI distribution
|
||||
app.use(loopback.static(SWAGGER_UI_ROOT));
|
||||
|
||||
|
|
|
@ -23,11 +23,16 @@ var classHelper = module.exports = {
|
|||
* @return {Object} API Declaration.
|
||||
*/
|
||||
generateAPIDoc: function(aClass, opts) {
|
||||
var resourcePath = urlJoin('/', aClass.name);
|
||||
if(aClass.http && aClass.http.path) {
|
||||
resourcePath = aClass.http.path;
|
||||
}
|
||||
|
||||
return {
|
||||
apiVersion: opts.version,
|
||||
swaggerVersion: opts.swaggerVersion,
|
||||
basePath: opts.basePath,
|
||||
resourcePath: urlJoin('/', opts.resourcePath),
|
||||
resourcePath: urlJoin('/', resourcePath),
|
||||
apis: [],
|
||||
consumes: aClass.http.consumes || opts.consumes,
|
||||
produces: aClass.http.produces || opts.produces,
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var _cloneDeep = require('lodash.clonedeep');
|
||||
var _pick = require('lodash.pick');
|
||||
var _cloneDeep = require('lodash').cloneDeep;
|
||||
var _pick = require('lodash').pick;
|
||||
var translateDataTypeKeys = require('./translate-data-type-keys');
|
||||
var typeConverter = require('./type-converter');
|
||||
|
||||
|
@ -21,8 +21,15 @@ var modelHelper = module.exports = {
|
|||
*/
|
||||
generateModelDefinition: function generateModelDefinition(modelClass, definitions) {
|
||||
var def = modelClass.definition;
|
||||
var name = def.name;
|
||||
var out = definitions || {};
|
||||
|
||||
if (!def) {
|
||||
// The model does not have any definition, it was most likely
|
||||
// created as a placeholder for an unknown property type
|
||||
return out;
|
||||
}
|
||||
|
||||
var name = def.name;
|
||||
if (out[name]) {
|
||||
// The model is already included
|
||||
return out;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
var debug = require('debug')('loopback:explorer:routeHelpers');
|
||||
var _cloneDeep = require('lodash.clonedeep');
|
||||
var _assign = require('lodash.assign');
|
||||
var _cloneDeep = require('lodash').cloneDeep;
|
||||
var _assign = require('lodash').assign;
|
||||
var modelHelper = require('./model-helper');
|
||||
var typeConverter = require('./type-converter');
|
||||
|
||||
|
@ -125,17 +125,9 @@ var routeHelper = module.exports = {
|
|||
|
||||
var responseDoc = modelHelper.LDLPropToSwaggerDataType(returns);
|
||||
|
||||
// Note: Swagger Spec does not provide a way how to specify
|
||||
// that the responseModel is "array of X". However,
|
||||
// Swagger UI converts Arrays to the item types anyways,
|
||||
// therefore it should be ok to do the same here.
|
||||
var responseModel = responseDoc.type === 'array' ?
|
||||
responseDoc.items.type : responseDoc.type;
|
||||
|
||||
var responseMessages = [{
|
||||
code: route.returns && route.returns.length ? 200 : 204,
|
||||
message: 'Request was successful',
|
||||
responseModel: responseModel
|
||||
message: 'Request was successful'
|
||||
}];
|
||||
|
||||
if (route.errors) {
|
||||
|
@ -145,18 +137,21 @@ var routeHelper = module.exports = {
|
|||
var apiDoc = {
|
||||
path: routeHelper.convertPathFragments(route.path),
|
||||
// Create the operation doc.
|
||||
// Note that we are not calling `extendWithType`, as the response type
|
||||
// is specified in the first response message.
|
||||
operations: [{
|
||||
// We are using extendWithType to use `type` for the top-level (200)
|
||||
// response type. We use responseModels for error responses.
|
||||
// see https://github.com/strongloop/loopback-explorer/issues/75
|
||||
operations: [routeHelper.extendWithType({
|
||||
method: routeHelper.convertVerb(route.verb),
|
||||
// [rfeng] Swagger UI doesn't escape '.' for jQuery selector
|
||||
nickname: route.method.replace(/\./g, '_'),
|
||||
// [strml] remove leading model name from op, swagger uses leading
|
||||
// path as class name so it remains unique between models.
|
||||
// route.method is always #{className}.#{methodName}
|
||||
nickname: route.method.replace(/.*?\./, ''),
|
||||
parameters: accepts,
|
||||
responseMessages: responseMessages,
|
||||
summary: typeConverter.convertText(route.description),
|
||||
notes: typeConverter.convertText(route.notes),
|
||||
deprecated: route.deprecated
|
||||
}]
|
||||
}, returns)]
|
||||
};
|
||||
|
||||
return apiDoc;
|
||||
|
|
|
@ -9,7 +9,7 @@ module.exports = Swagger;
|
|||
*/
|
||||
var path = require('path');
|
||||
var urlJoin = require('./url-join');
|
||||
var _defaults = require('lodash.defaults');
|
||||
var _defaults = require('lodash').defaults;
|
||||
var classHelper = require('./class-helper');
|
||||
var routeHelper = require('./route-helper');
|
||||
var modelHelper = require('./model-helper');
|
||||
|
@ -98,7 +98,11 @@ function Swagger(loopbackApplication, swaggerApp, opts) {
|
|||
addTypeToModels(type);
|
||||
});
|
||||
|
||||
if (routeDoc.type === 'array') {
|
||||
addTypeToModels(routeDoc.items.type);
|
||||
} else {
|
||||
addTypeToModels(routeDoc.type);
|
||||
}
|
||||
|
||||
routeDoc.responseMessages.forEach(function(msg) {
|
||||
addTypeToModels(msg.responseModel);
|
||||
|
@ -152,6 +156,11 @@ function addRoute(app, uri, doc, opts) {
|
|||
var hasBasePath = Object.keys(doc).indexOf('basePath') !== -1;
|
||||
var initialPath = doc.basePath || '';
|
||||
|
||||
// Remove the trailing slash, see
|
||||
// https://github.com/strongloop/loopback-explorer/issues/48
|
||||
if (initialPath[initialPath.length-1] === '/')
|
||||
initialPath = initialPath.slice(0, -1);
|
||||
|
||||
app.get(urlJoin('/', uri), function(req, res) {
|
||||
|
||||
// There's a few forces at play that require this "hack". The Swagger spec
|
||||
|
@ -166,9 +175,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);
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var _cloneDeep = require('lodash.clonedeep');
|
||||
var _cloneDeep = require('lodash').cloneDeep;
|
||||
|
||||
// Keys that are different between LDL and Swagger
|
||||
var KEY_TRANSLATIONS = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "loopback-explorer",
|
||||
"version": "1.3.0",
|
||||
"version": "1.7.1",
|
||||
"description": "Browse and test your LoopBack app's APIs",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
@ -23,7 +23,7 @@
|
|||
"devDependencies": {
|
||||
"loopback": "^2.14.0",
|
||||
"mocha": "^2.1.0",
|
||||
"supertest": "~0.15.0",
|
||||
"supertest": "^0.15.0",
|
||||
"chai": "^2.1.1"
|
||||
},
|
||||
"license": {
|
||||
|
@ -33,10 +33,7 @@
|
|||
"dependencies": {
|
||||
"cors": "^2.5.3",
|
||||
"debug": "~2.1.2",
|
||||
"lodash.assign": "^3.0.0",
|
||||
"lodash.clonedeep": "^3.0.0",
|
||||
"lodash.defaults": "^3.0.0",
|
||||
"lodash.pick": "^3.0.0",
|
||||
"lodash": "^3.0.0",
|
||||
"swagger-ui": "~2.0.24"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>StrongLoop API Explorer</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='screen,print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='screen,print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/loopbackStyles.css' rel='stylesheet' type='text/css'/>
|
||||
<script type="text/javascript" src="lib/shred.bundle.js"></script>
|
||||
<script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Refactoring of inline script from index.html.
|
||||
/*global SwaggerUi, log, ApiKeyAuthorization, hljs, window, $ */
|
||||
$(function() {
|
||||
var lsKey = 'swagger_accessToken';
|
||||
$.getJSON('config.json', function(config) {
|
||||
log(config);
|
||||
loadSwaggerUi(config);
|
||||
|
@ -35,6 +36,14 @@ $(function() {
|
|||
$('#api_selector').submit(setAccessToken);
|
||||
$('#input_accessToken').keyup(onInputChange);
|
||||
|
||||
// Recover accessToken from localStorage if present.
|
||||
if (window.localStorage) {
|
||||
var key = window.localStorage.getItem(lsKey);
|
||||
if (key) {
|
||||
$('#input_accessToken').val(key).submit();
|
||||
}
|
||||
}
|
||||
|
||||
window.swaggerUi.load();
|
||||
}
|
||||
|
||||
|
@ -49,6 +58,11 @@ $(function() {
|
|||
accessToken = key;
|
||||
$('.accessTokenDisplay').text('Token Set.').addClass('set');
|
||||
$('.accessTokenDisplay').attr('data-tooltip', 'Current Token: ' + key);
|
||||
|
||||
// Save this token to localStorage if we can to make it persist on refresh.
|
||||
if (window.localStorage) {
|
||||
window.localStorage.setItem(lsKey, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var classHelper = require('../lib/class-helper');
|
||||
var expect = require('chai').expect;
|
||||
var _defaults = require('lodash.defaults');
|
||||
var _defaults = require('lodash').defaults;
|
||||
|
||||
describe('class-helper', function() {
|
||||
it('joins array descriptions', function() {
|
||||
|
@ -12,12 +12,32 @@ describe('class-helper', function() {
|
|||
|
||||
expect(doc.description).to.equal('line1\nline2');
|
||||
});
|
||||
|
||||
it('sets resourcePath from aClass.http.path', function() {
|
||||
var doc = generateAPIDoc({}, 'otherPath');
|
||||
|
||||
expect(doc.resourcePath).to.equal('/otherPath');
|
||||
});
|
||||
|
||||
it('sets resourcePath from aClass.name', function() {
|
||||
var doc = generateAPIDoc({});
|
||||
|
||||
expect(doc.resourcePath).to.equal('/test');
|
||||
});
|
||||
});
|
||||
|
||||
// Easy wrapper around createRoute
|
||||
function generateResourceDocAPIEntry(def) {
|
||||
return classHelper.generateResourceDocAPIEntry(_defaults(def, {
|
||||
http: { path: '/test' },
|
||||
ctor: { settings: { } },
|
||||
ctor: { settings: { } }
|
||||
}));
|
||||
}
|
||||
|
||||
function generateAPIDoc(def, httpPath) {
|
||||
return classHelper.generateAPIDoc(_defaults(def, {
|
||||
http: { path: httpPath || null },
|
||||
name: 'test',
|
||||
ctor: { settings: { } }
|
||||
}), {resourcePath: 'resources'});
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@ var loopback = require('loopback');
|
|||
var explorer = require('../');
|
||||
var request = require('supertest');
|
||||
var assert = require('assert');
|
||||
var path = require('path');
|
||||
var expect = require('chai').expect;
|
||||
var urlJoin = require('../lib/url-join');
|
||||
var os = require('os');
|
||||
|
||||
describe('explorer', function() {
|
||||
|
||||
|
@ -77,6 +80,83 @@ describe('explorer', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('removes trailing slash from baseUrl', function(done) {
|
||||
// SwaggerUI builds resource URL by concatenating basePath + resourcePath
|
||||
// Since the resource paths are always startign with a slash,
|
||||
// if the basePath ends with a slash too, an incorrect URL is produced
|
||||
var app = loopback();
|
||||
app.set('restApiRoot', '/');
|
||||
configureRestApiAndExplorer(app);
|
||||
|
||||
request(app)
|
||||
.get('/explorer/resources/products')
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
var baseUrl = res.body.basePath;
|
||||
var apiPath = res.body.apis[0].path;
|
||||
expect(baseUrl + apiPath).to.match(/http:\/\/[^\/]+\/products/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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 */' + os.EOL)
|
||||
.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' + os.EOL)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when specifying custom static file root directories', function() {
|
||||
var app;
|
||||
beforeEach(function() {
|
||||
app = loopback();
|
||||
});
|
||||
|
||||
it('should allow `uiDirs` to be defined as an Array', function(done) {
|
||||
app.use('/explorer', explorer(app, {
|
||||
uiDirs: [ path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui') ]
|
||||
}));
|
||||
|
||||
request(app).get('/explorer/')
|
||||
.expect(200)
|
||||
// expect the content of `dummy-swagger-ui/index.html`
|
||||
.expect('custom index.html' + os.EOL)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('should allow `uiDirs` to be defined as an String', function(done) {
|
||||
app.use('/explorer', explorer(app, {
|
||||
uiDirs: path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui')
|
||||
}));
|
||||
|
||||
request(app).get('/explorer/')
|
||||
.expect(200)
|
||||
// expect the content of `dummy-swagger-ui/index.html`
|
||||
.expect('custom index.html' + os.EOL)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
function givenLoopBackAppWithExplorer(explorerBase) {
|
||||
|
@ -88,7 +168,7 @@ describe('explorer', function() {
|
|||
}
|
||||
|
||||
function configureRestApiAndExplorer(app, explorerBase) {
|
||||
var Product = loopback.Model.extend('product');
|
||||
var Product = loopback.PersistedModel.extend('product');
|
||||
Product.attachTo(loopback.memory());
|
||||
app.model(Product);
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
custom index.html
|
|
@ -0,0 +1 @@
|
|||
/* custom swagger-ui file */
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var modelHelper = require('../lib/model-helper');
|
||||
var _defaults = require('lodash.defaults');
|
||||
var _defaults = require('lodash').defaults;
|
||||
var loopback = require('loopback');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
|
@ -198,6 +198,18 @@ describe('model-helper', function() {
|
|||
expect(Object.keys(defs)).has.property('length', 1);
|
||||
});
|
||||
|
||||
// https://github.com/strongloop/loopback-explorer/issues/71
|
||||
it('should skip unknown types', function() {
|
||||
var Model8 = loopback.createModel('Model8', {
|
||||
patient: {
|
||||
model: 'physician',
|
||||
type: 'hasMany',
|
||||
through: 'appointment'
|
||||
}
|
||||
});
|
||||
var defs = modelHelper.generateModelDefinition(Model8, {});
|
||||
expect(Object.keys(defs)).to.not.contain('hasMany');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hidden properties', function() {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var routeHelper = require('../lib/route-helper');
|
||||
var expect = require('chai').expect;
|
||||
var _defaults = require('lodash.defaults');
|
||||
var _defaults = require('lodash').defaults;
|
||||
|
||||
describe('route-helper', function() {
|
||||
it('returns "object" when a route has multiple return values', function() {
|
||||
|
@ -13,8 +13,8 @@ describe('route-helper', function() {
|
|||
{ arg: 'avg', type: 'number' }
|
||||
]
|
||||
});
|
||||
expect(doc.operations[0].type).to.equal(undefined);
|
||||
expect(getResponseType(doc.operations[0])).to.equal('object');
|
||||
expect(doc.operations[0].type).to.equal('object');
|
||||
expect(getResponseType(doc.operations[0])).to.equal(undefined);
|
||||
});
|
||||
|
||||
it('converts path params when they exist in the route name', function() {
|
||||
|
@ -61,12 +61,22 @@ describe('route-helper', function() {
|
|||
]
|
||||
});
|
||||
var opDoc = doc.operations[0];
|
||||
// Note: swagger-ui treat arrays of X the same way as object X
|
||||
expect(getResponseType(opDoc)).to.equal('customType');
|
||||
expect(getResponseType(opDoc)).to.equal(undefined);
|
||||
|
||||
// NOTE(bajtos) this would be the case if there was a single response type
|
||||
// expect(opDoc.type).to.equal('array');
|
||||
// expect(opDoc.items).to.eql({type: 'customType'});
|
||||
expect(opDoc.type).to.equal('array');
|
||||
expect(opDoc.items).to.eql({type: 'customType'});
|
||||
});
|
||||
|
||||
it('correctly converts return types (format)', function() {
|
||||
var doc = createAPIDoc({
|
||||
returns: [
|
||||
{arg: 'data', type: 'buffer'}
|
||||
]
|
||||
});
|
||||
var opDoc = doc.operations[0];
|
||||
expect(opDoc.type).to.equal('string');
|
||||
expect(opDoc.format).to.equal('byte');
|
||||
});
|
||||
|
||||
it('includes `notes` metadata', function() {
|
||||
|
@ -149,11 +159,11 @@ describe('route-helper', function() {
|
|||
var doc = createAPIDoc({
|
||||
returns: [{ name: 'result', type: 'object', root: true }]
|
||||
});
|
||||
expect(doc.operations[0].type).to.eql('object');
|
||||
expect(doc.operations[0].responseMessages).to.eql([
|
||||
{
|
||||
code: 200,
|
||||
message: 'Request was successful',
|
||||
responseModel: 'object'
|
||||
message: 'Request was successful'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
@ -162,11 +172,11 @@ describe('route-helper', function() {
|
|||
var doc = createAPIDoc({
|
||||
returns: []
|
||||
});
|
||||
expect(doc.operations[0].type).to.eql('void');
|
||||
expect(doc.operations[0].responseMessages).to.eql([
|
||||
{
|
||||
code: 204,
|
||||
message: 'Request was successful',
|
||||
responseModel: 'void'
|
||||
message: 'Request was successful'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
@ -185,11 +195,24 @@ describe('route-helper', function() {
|
|||
responseModel: 'ValidationError'
|
||||
});
|
||||
});
|
||||
|
||||
it('route nickname does not include model name.', function() {
|
||||
var doc = createAPIDoc();
|
||||
expect(doc.operations[0].nickname).to.equal('get');
|
||||
});
|
||||
|
||||
it('route nickname with a period is shorted correctly', function() {
|
||||
// Method is built by remoting to always be #{className}.#{methodName}
|
||||
var doc = createAPIDoc({
|
||||
method: 'test.get.me'
|
||||
});
|
||||
expect(doc.operations[0].nickname).to.eql('get.me');
|
||||
});
|
||||
});
|
||||
|
||||
// Easy wrapper around createRoute
|
||||
function createAPIDoc(def) {
|
||||
return routeHelper.routeToAPIDoc(_defaults(def, {
|
||||
return routeHelper.routeToAPIDoc(_defaults(def || {}, {
|
||||
path: '/test',
|
||||
verb: 'GET',
|
||||
method: 'test.get'
|
||||
|
|
|
@ -92,6 +92,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() {
|
||||
|
|
Loading…
Reference in New Issue