Allow LoopBack developers to add custom Swagger extensions to the output produced by loopback-swagger, for example metadata consumes by IBM API Connect.
The proposal we are going to implement:
If we look at the swagger file generated by apic loopback (and friends), i.e. definitions/{name}.yaml, we can see that it contains many custom configuration specified via x-ibm-* extensions. The goal is to allow LoopBack applications to specify this extra metadata together with regular app/model/datasource configuration in such way that loopback-swagger will be able to pick it up and include in the produced swagger spec.
The general rule is that any properties with a name starting with x- will be copied from remoting metadata to swagger.
1) "a definition", "an operation" and "a parameter"
The implementation for "a definition", "an operation" and "a parameter" is straightforward as we already have matching concepts in loopback (a model, a method, an "accepts" parameter).
Here is an example of common/models/my-model.json that adds "x-ibm-def" to a definition, "x-ibm-op" to an operation and "x-ibm-par" to a parameter:
{
"name": "MyModel",
"properties": {
"name": "string"
},
"x-ibm-def": "custom data, may be an object too",
"methods": {
"greet": {
"isStatic": true,
"x-ibm-op": "custom data, may be an object too",
"accepts": {
"arg": "message",
"type": "string",
"required": true,
"x-ibm-par": "custom data, may be an object too"
}
}
}
}
The remaining two places are a bit more tricky.
2) A return value
A return value (response body) may be created dynamically from multiple callback arguments, as shown here:
function multi(cb) {
cb(null, 10, "bunnies");
}
multi.returns = [
{ arg: 'count', type: Number },
{ arg: 'kind', type: String }
];
I suppose the easiest solution is to copy all extensions from the first "returns" argument and ignore any extensions specified on the subsequent args. This works particularly well for built-in CRUD methods that have only a single return arg with root:true.
3) doc root
ATM, I think we don't have any app-wide remoting metadata. Concepts that are close but not the same: remoting section in server/config.json (which will be probably deprecated/removed soon), params for the loopback#rest middleware as specified in server/middleware.json.
I think server/config.json is a good place where to put top-level swagger extensions. We can either reuse existing remoting section, or create a new one called e.g. swagger or swagger-spec.
An example of server/app.config:
{
"restApiRoot": "/api",
"host": "127.0.0.1",
"port": 3000,
"swagger": {
"info": {
"x-ibm-name": "my APIC app"
},
"x-ibm-configuration": {
"testable": true,
"etc.": "etc."
}
}
}
4) customizing built-in models
As proposed in the first example, one can add custom swagger extensions to remoting metadata provided in mymodel.json. However, built-in CRUD methods are inherited, they don't have any description in the "methods" section and thus we don't have the place to add these custom extensions. Relation methods are even more complicated!
A possible solution is to extend the mechanism processing "methods" section and allow subclasses to partially extend and/or overwrite remoting metadata provided by the base (parent) model.
Example:
{
"name": "Car",
"base": "PersistedModel",
"methods": {
"find": {
"isStatic": true,
"x-ibm-operation-flag": true
}
}
}
The implementation will then check if there is an existing static "find" method and if found, then the metadata will be applied for this existing method.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Most helpful comment
The proposal we are going to implement:
If we look at the swagger file generated by
apic loopback(and friends), i.e.definitions/{name}.yaml, we can see that it contains many custom configuration specified viax-ibm-*extensions. The goal is to allow LoopBack applications to specify this extra metadata together with regular app/model/datasource configuration in such way that loopback-swagger will be able to pick it up and include in the produced swagger spec.The general rule is that any properties with a name starting with
x-will be copied from remoting metadata to swagger.1) "a definition", "an operation" and "a parameter"
The implementation for "a definition", "an operation" and "a parameter" is straightforward as we already have matching concepts in loopback (a model, a method, an "accepts" parameter).
Here is an example of
common/models/my-model.jsonthat adds "x-ibm-def" to a definition, "x-ibm-op" to an operation and "x-ibm-par" to a parameter:The remaining two places are a bit more tricky.
2) A return value
A return value (response body) may be created dynamically from multiple callback arguments, as shown here:
I suppose the easiest solution is to copy all extensions from the first "returns" argument and ignore any extensions specified on the subsequent args. This works particularly well for built-in CRUD methods that have only a single return arg with
root:true.3) doc root
ATM, I think we don't have any app-wide remoting metadata. Concepts that are close but not the same:
remotingsection inserver/config.json(which will be probably deprecated/removed soon),paramsfor theloopback#restmiddleware as specified inserver/middleware.json.I think
server/config.jsonis a good place where to put top-level swagger extensions. We can either reuse existingremotingsection, or create a new one called e.g.swaggerorswagger-spec.An example of
server/app.config:4) customizing built-in models
As proposed in the first example, one can add custom swagger extensions to remoting metadata provided in
mymodel.json. However, built-in CRUD methods are inherited, they don't have any description in the "methods" section and thus we don't have the place to add these custom extensions. Relation methods are even more complicated!A possible solution is to extend the mechanism processing "methods" section and allow subclasses to partially extend and/or overwrite remoting metadata provided by the base (parent) model.
Example:
The implementation will then check if there is an existing static "find" method and if found, then the metadata will be applied for this existing method.