Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
88c330a
Add indication of response being a collection
shelbys Jul 9, 2014
a9c1152
Correct description of collections of object and nested
shelbys Jul 10, 2014
5a07b80
Upgraded to latest Swagger-UI for 1.2 support
shelbys Jul 13, 2014
59afbb1
Upgraded to latest Swagger-UI for 1.2 support
shelbys Jul 13, 2014
0f4bf48
Updated to latest Swagger-UI for better responseMessage signature han…
shelbys Jul 15, 2014
ed04446
Reverted to use special loading logic from loopback-explorer
shelbys Jul 15, 2014
0e22384
Reverted to use special loading logic from loopback-explorer
shelbys Jul 15, 2014
15aa4e9
Ensure Response Content Type is shown regardless of Response Class
shelbys Jul 16, 2014
17e8b7b
Added support for toggling Model and Schema, and added support for pr…
shelbys Jul 29, 2014
c1a0eb5
Upgraded to SwaggerUI 2.0.18
shelbys Jul 30, 2014
2c737d4
Merge remote-tracking branch 'upstream/master'
shelbys Aug 5, 2014
3dc7de6
Ported extensions for more Swagger 1.2 metadata, returns+errors as re…
shelbys Aug 5, 2014
28d293b
Merge remote-tracking branch 'upstream/master'
shelbys Aug 5, 2014
86d7958
Load swagger ui from `swagger-ui` package instead.
Jul 4, 2014
696e387
Corrected issues with merge of 2.x changes
shelbys Aug 5, 2014
24d77f0
Corrected issues with merge of 2.x changes
shelbys Aug 5, 2014
ae8858c
Corrected issues with merge of 2.x changes
shelbys Aug 5, 2014
9693150
Corrected issues with merge of 2.x changes
shelbys Aug 5, 2014
1a96d84
Corrected issues with merge of 2.x changes
shelbys Aug 5, 2014
c6754ba
Ported prepareDataType() from old strong-remoting:ext/swagger.js
shelbys Aug 5, 2014
cf3e616
Corrected default for consumes+produces
shelbys Aug 6, 2014
1eddcad
Corrected generateModelDefinition() to scan for model references in r…
shelbys Aug 6, 2014
5ef5bae
Corrected prepareDataType() to handle collections and nesting, and ch…
shelbys Aug 6, 2014
820c51f
Corrected generateModelDefinition() to scan for model references nest…
shelbys Aug 6, 2014
76057a2
Changed to possibly pull model description from ctor.settings
shelbys Aug 7, 2014
a4ab802
Removed branch-lock for loopback
shelbys Aug 7, 2014
d7909e8
Merge pull request #1 from shelbys/loopback-v2
shelbys Aug 7, 2014
464e37c
Changed addRoute() to honor X-Forwarded-Host
shelbys Aug 26, 2014
240898e
Added support for scanning accepts params for Model references
shelbys Sep 18, 2014
2d6f7ae
Added padding to content well in order to counteract changes in Swagg…
shelbys Sep 30, 2014
8563dd0
Merge remote-tracking branch 'upstream/master'
shelbys Oct 7, 2014
7f4e8b3
Corrected merge issues
shelbys Oct 7, 2014
fd30b2d
Protected against non-Model generation requests
shelbys Oct 7, 2014
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ lib-cov
*.pid
*.gz

.idea
pids
logs
results

npm-debug.log
node_modules

LoopBackExplorer.iml
4 changes: 2 additions & 2 deletions lib/class-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var classHelper = module.exports = {
*/
generateAPIDoc: function(aClass, opts) {
return {
apiVersion: opts.version,
apiVersion: opts.version || '1',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shelbys what is the rationale for this, why don't you fill the version number in explorer options?

I would prefer to use 1.0 as the default value, as it's closer to http://semver.org/. Any objections?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are actually using the version number from package.json or 1.0.0 now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - I believe I was running into something referencing the value without checking for its presence. This may not be necessary any longer. I used '1' instead of '1.0', because path-based versioning is generally done using integer versions only

swaggerVersion: opts.swaggerVersion,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we are at fixing version numbers, I am proposing to fill 1.2 as swaggerVersion and deprecate the setting opts.swaggerVersion. It's the loopback explorer who decided what Swagger version it is supporting, not the user of this module.

@STRML @raymondfeng any objections?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that sounds good. Any other value than 1.2 would be wrong here.
On Oct 13, 2014 3:36 PM, "Miroslav Bajtoš" notifications@github.com wrote:

In lib/class-helper.js:

@@ -23,7 +23,7 @@ var classHelper = module.exports = {
*/
generateAPIDoc: function(aClass, opts) {
return {

  •  apiVersion: opts.version,
    
  •  apiVersion: opts.version || '1',
    
    swaggerVersion: opts.swaggerVersion,

While we are at fixing version numbers, I am proposing to fill 1.2 as
swaggerVersion and deprecate the setting opts.swaggerVersion. It's the
loopback explorer who decided what Swagger version it is supporting, not
the user of this module.

@STRML https://github.com/STRML @raymondfeng
https://github.com/raymondfeng any objections?


Reply to this email directly or view it on GitHub
https://github.com/strongloop/loopback-explorer/pull/52/files#r18769348.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current master was already providing a hard-coded version string 1.2. I added code to print a warning when the user tries to override - see #61.

basePath: opts.basePath,
resourcePath: urlJoin('/', opts.resourcePath),
Expand All @@ -43,7 +43,7 @@ var classHelper = module.exports = {
generateResourceDocAPIEntry: function(aClass) {
return {
path: aClass.http.path,
description: aClass.ctor.sharedCtor && aClass.ctor.sharedCtor.description
description: aClass.ctor.settings.description || aClass.ctor.sharedCtor && aClass.ctor.sharedCtor.description
};
}
};
67 changes: 58 additions & 9 deletions lib/model-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ var modelHelper = module.exports = {
* @return {Object} Associated model definition.
*/
generateModelDefinition: function generateModelDefinition(modelClass, definitions) {
var processType = function(app, modelName, referencedModels) {
if (app && modelName) {
if (modelName.indexOf('[') == 0) {
modelName = modelName.replace(/[\[\]]/g, '');
}
var model = app.models[modelName];
if (model && referencedModels.indexOf(model) === -1) {
referencedModels.push(model);
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shelbys this looks suspicious to me. Can you describe a scenario that needs this change? AFAIK, def.properties is always built from def.rawProperties by loopback-datasource-juggler.

/cc @raymondfeng thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preferring rawProperties over properties has a significant impact: properties entries are always an object with a type property, e.g. { type: 'string' }. On the other hand, rawProperties contain whatever the user specified, e.g. a string or an array.

If we want to support rawProperties, then we have to duplicate the logic from ModelBuilder.prototype.resolveType() to support all different flavours of property definitions, which is something I would rather avoid.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Github is displaying an incorrect diff for me. Here is the target of my comments above:

-   var properties = _cloneDeep(def.properties);
+  var properties = _cloneDeep(def.rawProperties || def.properties);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am rejecting this part of the PR. @shelbys if you can explain why this change is necessary, I am happy to reconsider.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - I switched to rawProperties in order to have access to the type for each property on the model in order to detect nested model references and have them properly displayed in SwaggerUI. For instance, we have a Purchase which has a property of type Contact which has a property of type Address, all being custom Models

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the current master already handles nested model references - see lib/model-helper.js#L73-L86.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - Please confirm that master handles all of: 1) recursively nested references to 2) Models and 3) Arrays of Models in 4) properties, 5) modelTo and modelThrough relations, 6) accepts, 7) returns and 8) errors

processType() is handling Array of Model in the style of '[Model]' and avoids processing primitive functions (e.g. Number(), String(), etc) , otherwise 73-76 look to do the same thing as those referenced above

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please confirm that master handles all of: 1) recursively nested references to 2) Models and 3) Arrays of Models in 4) properties, 5) modelTo and modelThrough relations, 6) accepts, 7) returns and 8) errors

See #61.

}

var def = modelClass.definition;
var name = def.name;
var out = definitions || {};
Expand All @@ -27,15 +39,15 @@ var modelHelper = module.exports = {
}
var required = [];
// Don't modify original properties.
var properties = _cloneDeep(def.properties);
var properties = _cloneDeep(def.rawProperties || def.properties);

var referencedModels = [];
// Add models from settings
if (def.settings && def.settings.models) {
for (var m in def.settings.models) {
var model = modelClass[m];
if (typeof model === 'function' && model.modelName) {
if (referencedModels.indexOf(model) === -1) {
if (model && referencedModels.indexOf(model) === -1) {
referencedModels.push(model);
}
}
Expand All @@ -58,6 +70,10 @@ var modelHelper = module.exports = {

// Eke a type out of the constructors we were passed.
prop = modelHelper.LDLPropToSwaggerDataType(prop);
processType(modelClass.app, prop.type, referencedModels);
if (prop.items) {
processType(modelClass.app, prop.items.type, referencedModels);
}

// Required props sit in a per-model array.
if (prop.required || (prop.id && !prop.generated)) {
Expand Down Expand Up @@ -95,15 +111,43 @@ var modelHelper = module.exports = {
// Generate model definitions for related models
for (var r in modelClass.relations) {
var rel = modelClass.relations[r];
if (rel.modelTo){
generateModelDefinition(rel.modelTo, out);
if (rel.modelTo && referencedModels.indexOf(rel.modelTo) === -1) {
referencedModels.push(rel.modelTo);
}
if (rel.modelThrough && referencedModels.indexOf(rel.modelThrough) === -1) {
referencedModels.push(rel.modelThrough);
}
if (rel.modelThrough) {
generateModelDefinition(rel.modelThrough, out);
}

if (modelClass.sharedClass) {
var remotes = modelClass.sharedClass.methods();
for (var remoteIdx in remotes) {
var remote = remotes[remoteIdx];
var accepts = remote.accepts;
if (accepts) {
for (var acceptIdx in accepts) {
processType(modelClass.app, accepts[acceptIdx].type, referencedModels);
}
}
var returns = remote.returns;
if (returns) {
for (var returnIdx in returns) {
processType(modelClass.app, returns[returnIdx].type, referencedModels);
}
}
var errors = remote.errors;
if (errors) {
for (var errorIdx in errors) {
processType(modelClass.app, errors[errorIdx].responseModel, referencedModels);
}
}
}
}

for (var i = 0, n = referencedModels.length; i < n; i++) {
generateModelDefinition(referencedModels[i], out);
if (referencedModels[i].definition) {
generateModelDefinition(referencedModels[i], out);
}
}
return out;
},
Expand All @@ -113,7 +157,7 @@ var modelHelper = module.exports = {
* get a string type.
* @param {*} propType Prop type description.
* @return {String} Prop type string.
*/
*/
getPropType: function getPropType(propType) {
if (typeof propType === 'function') {
// See https://github.com/strongloop/loopback-explorer/issues/32
Expand All @@ -126,7 +170,7 @@ var modelHelper = module.exports = {
},

isHiddenProperty: function(definition, propName) {
return definition.settings &&
return definition.settings &&
Array.isArray(definition.settings.hidden) &&
definition.settings.hidden.indexOf(propName) !== -1;
},
Expand All @@ -135,6 +179,11 @@ var modelHelper = module.exports = {
// Swagger spec.
// https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#431-primitives
LDLPropToSwaggerDataType: function LDLPropToSwaggerDataType(prop) {
if (typeof prop === 'string') {
prop = {
type: prop
}
}
var out = _cloneDeep(prop);
out.type = modelHelper.getPropType(out.type);

Expand Down
87 changes: 75 additions & 12 deletions lib/route-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,71 @@ var routeHelper = module.exports = {
* See https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#523-operation-object
*/
routeToAPIDoc: function routeToAPIDoc(route, classDef) {
/**
* Converts from an sl-remoting data type to a Swagger dataType.
*/
function prepareDataType(type) {
if (!type) {
return 'void';
}

if(Array.isArray(type)) {
if (type.length > 0) {
if (typeof type[0] === 'string') {
return '[' + type[0] + ']';
} else if (typeof type[0] === 'function') {
return '[' + type[0].name + ']';
} else if (typeof type[0] === 'object') {
if (typeof type[0].type === 'function') {
return '[' + type[0].type.name + ']';
} else {
return '[' + type[0].type + ']';
}
} else {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shelbys You are removing type from the Operation metadata, what is the reason for that? Is it because the return type is specified by the responseMessage for the status code 200, as introduced above?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems this is actually correct, the spec for Operation Object does not mention any type field.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it does not mention the type field in the operation description, but it says:

This object includes the Data Type Fields in order to describe the return value of the operation. The type field MUST be used to link to other models.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swagger provides two ways for specifying the response type:

  1. globally in operations[].type
  2. per-response-code in responseMessages[].responseModel

screen shot 2014-10-14 at 13 36 43

In the screenshot above, operations[].type is displayed as "Response Class" at the top, responseMessages[].responseModel is displayed in "Response Model" inside "Response Messages" section at the bottom.

I'll submit a pull request that keeps the response model in both places. We can discuss what's the best solution in the PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR: #61

Please post any replies there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - We switched to always using responseMessage.responseModel, because we use different Models by Status, including a custom, reusable Model for Error responses. This is more natural for many of our endpoints that aren't CRUD-related. Also, I believe it better uses the space visually and with less confusion.

You could change it to use type if there aren't multiple possible, but we'd never use that since we always have multiple

For reference, see: https://developer.godaddy.com/doc#!/shoppers/Subaccount_create

return '[' + type + ']';
}
}
return 'array';
}

// TODO(schoon) - Add support for complex dataTypes, "models", etc.
switch (type) {
case 'Array':
return 'array';
case 'Boolean':
return 'boolean';
case 'buffer':
return 'string';
case 'Date':
return 'date';
case 'number':
case 'Number':
return 'double';
case 'Object':
return 'object';
case 'String':
return 'string';
}

return type;
}

var returnDesc;

// Some parameters need to be altered; eventually most of this should
// be removed.
var accepts = routeHelper.convertAcceptsToSwagger(route, classDef);
var returns = routeHelper.convertReturnsToSwagger(route, classDef);
var responseMessages = [
{
code: 200,
message: 'Request was successful',
responseModel: returns.model || prepareDataType(returns.type) || 'void'
}
];
if (route.errors) {
responseMessages.push.apply(responseMessages, route.errors);
}

debug('route %j', route);

Expand All @@ -128,17 +187,15 @@ var routeHelper = module.exports = {
// `items` and `format` fields.
operations: [routeHelper.extendWithType({
method: routeHelper.convertVerb(route.verb),
deprecated: route.deprecated,
// [rfeng] Swagger UI doesn't escape '.' for jQuery selector
nickname: route.method.replace(/\./g, '_'),
// Per the spec:
// https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#523-operation-object
// This is the only object that may have a type of 'void'.
type: returns.model || returns.type || 'void',
parameters: accepts,
// TODO(schoon) - We don't have descriptions for this yet.
responseMessages: [],
summary: route.description, // TODO(schoon) - Excerpt?
notes: '' // TODO(schoon) - `description` metadata?
notes: route.notes, // TODO(schoon) - `description` metadata?
consumes: ['application/json', 'application/xml', 'text/xml'],
produces: ['application/json', 'application/javascript', 'application/xml', 'text/javascript', 'text/xml'],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are the values for consumes and produces different?

The produced content types depends on the version of strong-remoting and can be extended by remote methods, as they may decide to use a custom content type. For the sake of simplicity, I am ok with ignoring this complexity and reporting only the base types supported by strong-remoting OOTB.

@raymondfeng @ritch @STRML thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shelbys are you including 'application/javascript', 'text/javascript' to support JSONP requests? (Best Content-Type to serve JSONP)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, consumes and produces are already added to the resource (class), there is no need to explicitly add them to all routes here. However, we still need to add new types - see #58

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this comment as resolved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - Yes, I added those to support JSONP, and I only put them on produces, because I didn't have a reason to accept JSONP vs plain JSON

parameters: accepts,
responseMessages: responseMessages
})]
};

Expand Down Expand Up @@ -192,15 +249,21 @@ var routeHelper = module.exports = {
}

var out = {
paramType: paramType || type,
name: name,
description: accepts.description,
type: accepts.type,
required: !!accepts.required,
paramType: paramType || type,
type: accepts.type,
$ref: accepts.model,
items: accepts.items,
uniqueItems: accepts.uniqueItems,
format: accepts.format,
pattern: accepts.pattern,
defaultValue: accepts.defaultValue,
enum: accepts.enum,
minimum: accepts.minimum,
maximum: accepts.maximum,
allowMultiple: false
allowMultiple: accepts.allowMultiple,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@STRML @raymondfeng I need your help here as my knowledge of Swagger is not good enough.

Metadata like type, format and items is filled by routeHelper.extendWithType. Should we allow the developer to override this information? Or should we treat the values provided by the developer as a default and override them in extendWithType?

How about the new metadata - $ref? According to the spec, this is somewhat opposite of type, i.e. only one of them should be used.

The following metadata is not inferred from the type (yet) and thus it's IMO ok to customise them: pattern, enum, and uniqueItems. It would be better to support them directly in LDL and strong-remoting, but that's out of scope of this PR.

However, it leads me to the conclusion, that values specified in remoting metadata should be treated as a default and they should be overridden by extendWithType. That way when we add support in LDL, the swagger spec generated by loopback-explorer will describe the real constraints as seen by loopback.

I have no idea how to treat allowMultiple. Here is the spec:

Another way to allow multiple values for a "query" parameter. If used, the query parameter may accept comma-separated values. The field may be used only if paramType is "query", "header" or "path".

It seems to me that this flag depends very much on what strong-remoting is willing to accept and process. If we support comma-separated values and parse them into an array, then this should be always true for relevant param types. If we don't support it, then this should be always false. Unless I am interpreting this in a completely wrong way.

Thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raymondfeng @STRML ping. This is the last part of this PR that needs to be ported.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos I agree with you on how we should deal with allowMultiple. It should be false unless strong-remoting starts to support it for string[] types.

Swagger uses JSON schema for typing properties. There are three styles:

  1. Simple type: {"type": "string"}
  2. Array type: {"type": "array", "items": {"type": "string"}}
  3. Object type: {"type": {"$ref": "#models/MyModel"}}

$ref is a JSON schema construct to reference a JSON model by pointer, for example, "$ref": "#/models/MyModel". I'm not sure if accepts.model is in that format.

My take is to use LDL type information and translate them into JSON schema.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented in #64.

The following fields are copied from LDL to Swagger:

      'format',
      'defaultValue', // "default" in LDL
      'enum',
      'minimum', // "min" in LDL
      'maximum', // "max" in LDL
      'uniqueItems',
      // loopback-explorer extensions
      'length',
      // https://www.npmjs.org/package/swagger-validation
      'pattern'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - Are you guys using swagger-validation instead of jsonschema? If so, we may want to compare notes on pros/cons, we went with the latter to have a broader, isomorphic solution. However, it would probably be better for us to both contribute to one schema validation solution

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK we don't use either. I was trying to find out what part of Swagger is using the field pattern and found swagger-validation. My line of thinking was that if nobody supports pattern in swagger types, then there is no point in including it in the response, since it is not defined in Swagger Spec standard.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - I took pattern from JSON Schema and it's part of Swagger Spec 2.0

description: accepts.description
};

out = routeHelper.extendWithType(out);
Expand Down
21 changes: 11 additions & 10 deletions lib/swagger.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ function Swagger(loopbackApplication, swaggerApp, opts) {
basePath: loopbackApplication.get('restApiRoot') || '/api',
resourcePath: 'resources',
// Default consumes/produces
consumes: ['application/json', 'application/x-www-form-urlencoded'],
produces: ['application/json'],
consumes: ['application/json', 'application/x-www-form-urlencoded', 'application/xml', 'text/xml'],
produces: ['application/json', 'application/javascript', 'application/xml', 'text/javascript', 'text/xml'],
version: getVersion()
});

Expand Down Expand Up @@ -100,9 +100,9 @@ function addRoute(app, uri, doc, opts) {
// know that header at the time the data is built.
if (hasBasePath) {
var headers = req.headers;
var host = headers.Host || headers.host;
doc.basePath = (opts.protocol || req.protocol) + '://' +
host + initialPath;
var host = headers['x-forwarded-host'] || headers['X-Forwarded-Host'] || headers.Host || headers.host;
var protocol = headers['x-forwarded-proto'] || headers['X-Forwarded-Proto'] || opts.protocol || req.protocol
doc.basePath = protocol + '://' + host + initialPath;
}
res.status(200).send(doc);
});
Expand All @@ -118,13 +118,14 @@ function generateResourceDoc(opts) {
return {
swaggerVersion: opts.swaggerVersion,
apiVersion: opts.version,
apis: [],
// See https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#513-info-object
info: opts.apiInfo
info: opts.apiInfo,
// TODO Authorizations
// https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#514-authorizations-object
// TODO Produces/Consumes
// https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#52-api-declaration
consumes: ['application/json', 'application/xml', 'text/xml'],
produces: ['application/json', 'application/javascript', 'application/xml', 'text/javascript', 'text/xml'],
apis: [],
models: opts.models

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shelbys According to Swagger Spec, the resource-listing object does not have any of the properties models, consumes, produces. Could you please explain why do you want to include them in the output?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am rejecting this part of the PR. @shelbys if you can explain why this change is necessary, I am happy to reconsider.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos I agree with you.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - I ported all of those from strong-remoting:ext/swagger.js, so they may not be necessary any longer. We don't currently depend on any of those specifically being in the Resource Listing

However, it seemed nice to set a default for consumes/produces, and then only have to override when different, especially since strong-remoting provides automatic conversion now. Also, we definitely have Models (Error, ErrorField) that would be nice to specify once, and then reuse across multiple resources, but Swagger wants Resources to be self-contained instead

};
}

Expand All @@ -137,7 +138,7 @@ function getVersion() {
try {
version = require(path.join(process.cwd(), 'package.json')).version;
} catch(e) {
version = '';
version = '1';
}
return version;
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"url": "https://github.com/strongloop/loopback-explorer/issues"
},
"devDependencies": {
"loopback": "1.x",
"loopback": "git+https://github.com/shelbys/loopback.git",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This MUST be fixed before landing the patch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raymondfeng - NOTE, we only forked loopback to easily reference our forks of the submodules (e.g. loopback-boot, loopback-explorer, strong-remoting, etc), so this change can be reverted before merge

"mocha": "~1.20.1",
"supertest": "~0.13.0",
"chai": "~1.9.1"
Expand All @@ -31,7 +31,7 @@
"url": "https://github.com/strongloop/loopback-explorer/blob/master/LICENSE"
},
"dependencies": {
"swagger-ui": "~2.0.18",
"swagger-ui": "git+https://github.com/shelbys/swagger-ui.git",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This MUST be fixed before landing the patch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raymondfeng - I'm not sure how to handle this one, because https://github.com/shelbys/swagger-ui will need to be merged into https://github.com/wordnik/swagger-ui and https://github.com/shelbys/swagger-js into https://github.com/wordnik/swagger-js in order to avoid a dependency on my fork. The functional changes in that fork should be universal, however there are some GoDaddy styling changes that have crept into the LESS/CSS, which will need to be done another way

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shelbys thanks for clarifying this, I presume it is up to us to submit the changes from your forks to the upstream repos and do any changes necessary to get the patches landed.

I am assuming the changes in swagger-ui and swagger-js are not tied to this pull request and thus can be upstreamed later, after this PR is resolved. Is that correct?

/cc @altsang @altsang I did not anticipate this task when estimating the effort, almost certainly I won't be able to prepare swagger-ui and swagger-js changes this sprint.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify.

I am assuming the changes in swagger-ui and swagger-js are not tied to this pull request and thus can be upstreamed later, after this PR is resolved. Is that correct?

My assumption is that if we land the changes in this PR and keep using the unmodified swagger-ui and swagger-js, things will continue to work. Therefore we can land this PR without having to wait until swagger-ui/js is updated. @shelbys Is that correct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos - We'll need to coordinate on the swagger-js and swagger-ui PRs, because you have style overrides and we have overrides, so we need to find a way for those to work together. We need a way to easily have local colors and fonts, but we should be able to agree on layout and spacing. If we can find a way to make the top-level and embedded cases both work and still have custom styling, I'm happy to strip out the styling changes from swagger-ui and then submit the rest.

I believe swagger-js only has universal changes, but includes an extension to Swagger Spec for documenting multiple basePaths for multiple environments. I'm not sure how they'll feel about the last, but am happy to keep it in my fork if necessary

The only functionality loss I see for sure is the Response Content Type not being shown for Response Messages, see: shelbys/swagger-ui@16ad569 Everything else seems to be bug fixes and usability

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this discussion to #66.

"debug": "~1.0.3",
"lodash.clonedeep": "^2.4.1",
"lodash.defaults": "^2.4.1",
Expand Down
5 changes: 5 additions & 0 deletions public/css/loopbackStyles.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
color: #080;
}

.contentWell {
padding-left: 30px;
padding-right: 30px;
}

/*
FIXME: Separate the overrides from the rest of the styles, rather than override screen.css entirely.
*/
Expand Down
Loading