apigee-127 / swagger-tools Goto Github PK
View Code? Open in Web Editor NEWA Node.js and browser module that provides tooling around Swagger.
License: MIT License
A Node.js and browser module that provides tooling around Swagger.
License: MIT License
This YAML:
# Example YAML for the bare minimum of required elements
swagger: '2.0'
info:
version: "1.0.0"
title: swagger
paths:
/:
get:
responses:
200:
description: Returns Swagger Schema
schema:
$ref: '#/definitions/Schema'
definitions:
Schema:
$ref: http://localhost:9000/schema.json
Throws this error:
code: "UNRESOLVABLE_MODEL"
message: "Model could not be resolved: #/definitions/http://localhost:9000/schema.json"
data: "#/definitions/http://localhost:9000/schema.json"
path: Array [3]
0: "definitions"
1: "Schema"
2: "$ref"
Found a bug in browser/swagger-tools.js
, on line 642:
if (!_.isUndefined(metadata.schema.required)) {
If the metadata doesn't have a schema, then an error is thrown because metadata.schema
is undefined
. Changing the line to this fixes the problem:
if (!_.isUndefined(metadata.schema) && !_.isUndefined(metadata.schema.required)) {
If I have YAML like the following:
/v2/users:
get:
blah blah blah blah
post:
blah blah blah blah
Then I expect that if I PUT or DELETE to /v2/users, that I will get a 405 (method not allowed) response.
In addition, the response should contain an "Allow" header as per RFC2616 which will tell me which operations are allowed on the resource.
We should use debug for logging.
Right now, operation parameters are validated using swagger-validator but we do not do any model validation in 1.2 and we do not do this or nested object validation as well.
As mentioned in PR #44, it would be nice for users to have access to more information when there are validation errors from the CLI. The standard is a --verbose
flag that will give more information so that's what we will do here.
It would be nice to support 2.0 as a work in progress if/when possible.
Right now, the operation path validation is pretty simple:
The problem is that it's very naive and any tools using this library will fail quickly without pretty solid validation. Here are the known places where operation path validation needs to be ramped up:
/some/{path}
and /some/{otherPath}
are technically the same)I have a swagger file. And I use this swagger.json to generate swagger.ui.
Then some errors crashed the app.
Property.sampleValue swagger-client.js:1027
Model.getSampleValue swagger-client.js:952
Property.sampleValue swagger-client.js:1028
Model.getSampleValue swagger-client.js:952
...
It seems like My model: MessageResource $ref itself. And this cause a Infinite loop in swagger-client.js.
{
"swagger": 2,
"info": {
"version": "0.0.1",
"title": "title"
},
"host": "localhost",
"basePath": "/",
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"x-volos-resources": {},
"paths": {
"/discussions": {
"post": {
"x-swagger-router-controller": "discussions",
"description": "Create a new discusion",
"operationId": "create",
"tags": [
"discussion"
],
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "DiscussionBody"
}
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "PostResponse"
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "ErrorResponse"
}
}
}
}
},
"/discussions/{discussionId}": {
"get": {
"x-swagger-router-controller": "discussions",
"description": "Get a discussion",
"operationId": "findById",
"tags": [
"discussion"
],
"parameters": [
{
"name": "discussionId",
"in": "path",
"description": "Id of discussion",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "Return a Discussion Resource",
"schema": {
"properties": {
"success": {
"type": "boolean"
},
"status": {
"type": "integer",
"format": "int32"
},
"content": {
"$ref": "DiscussionResource"
}
}
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "ErrorResponse"
}
}
}
}
},
"/discussions/{discussionId}/messages": {
"post": {
"x-swagger-router-controller": "messages",
"description": "Create a Message",
"operationId": "create",
"tags": [
"discussion",
"message"
],
"parameters": [
{
"name": "discussionId",
"in": "path",
"description": "Id of discussion",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "MessageBody"
}
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "PostResponse"
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "ErrorResponse"
}
}
}
},
"get": {
"x-swagger-router-controller": "messages",
"description": "Get all messages for a discussion",
"operationId": "getAllbyDiscussion",
"tags": [
"discussion",
"messages"
],
"parameters": [
{
"name": "discussionId",
"in": "path",
"description": "Id of discussion",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "Sucess",
"schema": {
"$ref": "MessagesResponse"
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "ErrorResponse"
}
}
}
}
},
"/discussions/{discussionId}/messages/{messageId}": {
"get": {
"x-swagger-router-controller": "messages",
"description": "Get a Message and it's children",
"operationId": "findById",
"tags": [
"discussion",
"messages"
],
"parameters": [
{
"name": "discussionId",
"in": "path",
"description": "Id of discussion",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "messageId",
"in": "path",
"description": "Id of message",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "A successufly response",
"schema": {
"properties": {
"success": {
"type": "boolean",
"description": "True or False if the request was a success"
},
"status": {
"type": "integer",
"description": "The HTTP status code"
},
"content": {
"$ref": "MessageResource"
}
}
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "ErrorResponse"
}
}
}
},
"put": {
"x-swagger-router-controller": "messages",
"description": "Update a message",
"operationId": "update",
"tags": [
"discussion",
"message"
],
"parameters": [
{
"name": "discussionId",
"in": "path",
"description": "Id of discussion",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "messageId",
"in": "path",
"description": "Id of message",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "MessageBody"
}
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"properties": {
"success": {
"type": "boolean",
"description": "True or False if the request was a success"
},
"status": {
"type": "integer",
"description": "The HTTP status code"
},
"content": {
"$ref": "MessageResource"
}
}
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "ErrorResponse"
}
}
}
},
"delete": {
"x-swagger-router-controller": "messages",
"description": "Delete a messsage",
"operationId": "delete",
"tags": [
"discussion",
"message"
],
"parameters": [
{
"name": "discussionId",
"in": "path",
"description": "Id of discussion",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "messageId",
"in": "path",
"description": "Id of message",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"properties": {
"success": {
"type": "boolean",
"description": "True or False if the request was a success"
},
"status": {
"type": "integer",
"description": "The HTTP status code"
}
}
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "ErrorResponse"
}
}
}
}
},
"/discussions/{discussionId}/messages/{messageId}/messages": {
"post": {
"x-swagger-router-controller": "messages",
"description": "Create a reply to a message. The message ID path param will be used as the parent id for the message.",
"operationId": "reply",
"tags": [
"discussion",
"message",
"reply"
],
"parameters": [
{
"name": "discussionId",
"in": "path",
"description": "Id of discussion",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "messageId",
"in": "path",
"description": "Id of message",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "MessageBody"
}
}
],
"responses": {
"200": {
"description": "Sucessful reply",
"schema": {
"$ref": "PostResponse"
}
}
}
}
}
},
"definitions": {
"MessagesResponse": {
"required": [
"messages"
],
"properties": {
"messages": {
"type": "array",
"items": {
"$ref": "MessageResource",
"minItems": 0,
"uniqueItems": true
}
}
}
},
"DiscussionResource": {
"required": [
"discussionId",
"remoteObjectName",
"remoteObjectId",
"messages"
],
"properties": {
"discussionId": {
"type": "integer",
"format": "int64"
},
"remoteObjectName": {
"type": "string"
},
"remoteObjectId": {
"type": "integer",
"format": "int64"
},
"messages": {
"type": "array",
"items": {
"$ref": "MessageResource",
"minItems": 0,
"uniqueItems": true
}
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
},
"createdBy": {
"type": "string",
"description": "The handle fo the user"
},
"updatedBy": {
"type": "string",
"description": "The handle fo the user"
}
}
},
"MessageResource": {
"required": [
"messageId",
"discussionId",
"content"
],
"properties": {
"messageId": {
"type": "integer",
"format": "int64"
},
"discussionId": {
"type": "integer",
"format": "int64"
},
"content": {
"type": "string"
},
"parentMessageId": {
"description": "The parent Message. optional",
"type": "integer",
"format": "int64"
},
"messages": {
"description": "The child messages",
"type": "array",
"items": {
"minItems": 0,
"uniqueItems": true,
"$ref": "MessageResource"
}
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
},
"createdBy": {
"type": "string",
"description": "The handle fo the user"
},
"updatedBy": {
"type": "string",
"description": "The handle fo the user"
}
}
},
"PostResponse": {
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"result": {
"properties": {
"success": {
"type": "boolean",
"description": "Was the request a success"
},
"status": {
"type": "integer",
"format": "int32",
"description": "The http status code"
}
}
}
}
},
"DiscussionBody": {
"required": [
"remoteObjectName",
"remoteObjectId"
],
"properties": {
"remoteObjectName": {
"description": "The type of object which a discussion is attached. for example challenge or submission",
"type": "string"
},
"remoteObjectId": {
"description": "The id of the remote object",
"type": "integer",
"format": "int64"
}
}
},
"MessageBody": {
"required": [
"content"
],
"properties": {
"content": {
"description": "The content of the message",
"type": "string"
}
}
},
"ErrorResponse": {
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32",
"description": "The http status code"
},
"message": {
"type": "string"
}
}
}
}
}
Enable a way to use all middleware with one app.use
invocation and some mix of arguments and an options object for disabling/configuring the middleware.
The sample snippets in the README are far from useful. We need real validation of the available APIs and middleware.
It would be nice to have fully baked code samples for the finished product in the Quick Start.
When the swagger-router middleware returns a 405 for a route match but not matching an operation method, we need to populate the Allow
header to include the list of allowable verbs.
I'm trying to get started building Apigee-127 proxies, but I'm having trouble figuring out how to map to response types defined by swagger, especially for error cases.
For example, take the "hello world" template code that is created when you do a127 project create <name>
, and make a single change: make the ?name=
query string parameter required.
If you do provide a valid name, the example project doesn't return a JSON structure I'd expect based on the HelloWorldResponse
in the swagger.yaml
. We just get a string saying "Hello, John"
instead of {"message": "Hello, John"}
. That can be easily fixed by updating the controller code, though it seems I have to personally ensure that my response body matches the swagger definition.
But if you don't provide a name, the swagger middleware throws a validation error (we made it a required value) and the controller isn't called. The end result does not match the ErrorResponse
type defined in the swagger.yaml
.
How is this meant to be handled? Is there something built into Apigee-127 for helping developers map to the swagger-defined responses?
I read this StackOverflow post and issue #37 but they only talked about the HTTP status code, not the response body.
I know I can create a middleware error handler in the app.js
file (something like app.use(function(err, req, res, next) {...});
and I see that I can get info from the req.swagger
object... But it seems like there's still a lot of work I'd have to do to determine how to map the error to the appropriate JSON body. And it could get much more complicated as I add additional routes since there is only one error handler.
It would be nice if the tooling helped out here somehow. Maybe transform errors into the default response types? Or allow controllers to define an error handler (or validationErrorHandler
) which the swagger middleware could call? Or am I just missing something?
The current code that checks the Content-Type
of a request against the consumes
of an operation does not handle the charset that can be included in the Content-Type
. (See rfc2616#sec3.7) We need to address this.
Reported by @grahamj
Instead of a singular directory for searching controllers, allow for searching an array of paths in order provided. This should not change how things worked prior but will be an extension to what is there now.
There is a problem with locating the schemas when installing the project via npm install swagger-tools
.
We need a way to register validators for vendor extensions. An example is to be able to validate missing controller definitions for swagger-router.
Instead of using a stub response for requests that are missing handlers, there should be a way to allow for returning mock responses:
To enable mock mode, you will pass mock-controllers
in the middleware options. If it is present regardless of value, mock mode will be enabled. Of course, if you want to implement a mock for your request, you'd pass in a directory where the mock controllers exist or the object mapping. (The value of the mock-controllers
option should work the same way the controllers
option works.)
As part of working on #1, a lot of code was kept logically together to make reading the code easier. This means that it might not necessarily be the most performant, for example we might be processing the same object more than once in cases. There are also other places where code could be cleaned up to be more consistent, written to add/avoid extra sanity checks, etc. Now that we have a working test suite covering all known validation needs, we can easily cleanup/refactor without worry of breaking something.
We need to make the API portion of swagger-tools available to the browser.
Whenever a stubbed handler is called for the swagger-router
middleware, we should add more detail to the response.
Right now, model resolution does not resolve references other than the inheritance chain. So model properties refer to a model type or arrays of items that are themselves model types contain the $ref
instead of the resolved model. (I think this also means we have an issue with our circular dependency tracking but we'll cross that bridge when we get there.)
Typical Node.js development uses req.params
to get access to request parameters. With swaggerMetadata, we intentionally namespaced them in req.swagger.params
. Let's run this by the community to see what their thoughts on doing this are.
We need to do more than just structural validation of the Swagger files:
***** The validation requires both the resource listing file and the API declaration/resource files
Errors
Warnings
To have consistency across all apigee-127 projects, this project needs to change its license.
The Swagger 2.0 specification allows you to use references in your parameters to point to other parts of the document. swagger-metadata
and swagger-validator
needs to be updated to handle this.
Right now, we're using jjve for taking the structural validation errors from jjv and making them a little more consumable. Right now, the path
portion of an error from jjve is a string. Not only does it have a big bug but the string-based path is not easily parseable. I'd really like to create paths as an array of path segments much like what substack/js-traverse does.
Swagger-Tools' validation logic incorrectly reports "Model could not be resolved" errors whenever URL references are used (e.g. $ref: "http://company.com/my/schema.json"
). Here's a screenshot from Swagger-Editor (which uses Swagger-Tools under the hood for validation):
Notice that Swagger-Tools is trying to find the URL reference under #/definitions/
. Here are the offending lines of code:
// Identify missing models (referenced but not declared)
if (_.isUndefined(metadata.schema)) {
_.each(metadata.refs, function (ref) {
createErrorOrWarning('UNRESOLVABLE_MODEL', 'Model could not be resolved: ' + modelId,
modelId, ref, result.errors);
});
}
swagger-router mock mode needs to implement support for the following:
Using the swagger UI to create a swagger.yaml with a couple of complex objects. When looking at the API documentation, the type is not identified. The yaml below produced the following API documentation. It identified object in the array simply as an object and of the type referenced by the GET response schema.
Is this just an API documentation fault?
swagger: 2.0
info:
version: "0.0.1"
title: glh 'ideal' open API
# during dev, should point to your local machine
host: api.glhhotels.com
# basePath prefixes all resource paths
basePath: /
#
schemes:
# tip: remove http to make production-grade
- http
- https
# format of bodies a client can send (Content-Type)
consumes:
- application/json
# format of the responses to the client (Accepts)
produces:
- application/json
x-volos-resources: {}
paths:
/preferences/{preferenceCode}:
# binds a127 app logic to a route
x-swagger-router-controller: preferencesController
x-volos-authorizations: {}
x-volos-apply: {}
get:
description: Returns the collection of preference codes and descriptions
# used as the method name of the controller
operationId: getPreferences
parameters:
- name: preferenceCode
in: path
description: An individual preference code. Add to limit the response to a single specific preference.
required: false
type: string
responses:
"200":
description: Success
schema:
# a pointer to a definition
$ref: PreferencesGetResponse
# responses may fall through to errors
default:
description: Error
schema:
$ref: StatusResponse
definitions:
#
StatusResponse:
required:
- statusCode
- statusDetails
properties:
statusCode:
type: string
statusDetails:
type: string
moreInfo:
type: array
items: {"label": string, "link": string}
###################################################################################
# Preference model
#
###################################################################################
PreferenceDetails:
required:
- preferenceType
- preferenceValue
properties:
preferenceTyoe:
type: string
preferenceDescription:
type: string
preferenceValue:
type: string
preferenceNotes:
type: string
PreferencesGetResponse:
required:
- status
- list
properties:
status:
type: object
$ref: StatusResponse
list:
type: array
items: {"object": "PreferenceDetails"}
It would be great to be able to run these Swagger tools from the CLI.
I'm facing the following error when I have a structured request body declared like:
/assignments:
x-swagger-router-controller: assignment
x-volos-authorizations: {}
x-volos-apply: {}
post:
description: Teacher creates a new assignment
operationId: create
parameters:
- name: authorization
in: header
description: The user access token
required: true
- name: body
in: body
description: The new assignment
required: true
schema:
$ref: Assignment
responses:
"200":
description: Success
schema:
$ref: AssignmentId
default:
description: Error
schema:
$ref: DefaultResponseError
Previously, if I did not provide a valid request body or no body at all, the application would issue a warning saying that I had made an invalid request.
Now it's giving me the following error:
Cannot read property '$ref' of null
However, I do have Assignment and Assignment schemas declared in the file.
I'm running [email protected]
.
It is my understanding that in some languages the swagger schema files are generated directly from class files, where fields and their types are derived from the underlying class file. In PHP (using https://github.com/zircote/swagger-php) this is not the case - the model schema files are generated from source code annotations. This leads to the possibility (due to a typo or other error) of a mismatch between what the API produces and what it says it will produce according its schema.
It would be very helpful if there was some way to validate that a message conforms to a given schema. This way, I could validate a sample of real API responses against their schemas as one way of checking for consistency. It would be good if the validator checked for missing and unexpected model properties as well as checking that property types are as expected.
Further, it may be useful during to development to treat invalid responses as an error in the application. This way errors in the API response (or the schema annotations) are caught sooner rather than later.
With Swagger 2.0, YAML comes into play and since people will constantly be loading JSON/YAML files, might as well make it easier by handling this in the APIs/middleware.
There are reusable pieces of code in the swagger-validator
middleware that should be bubbled up to a more generic middleware to make consuming Swagger information in route handlers and other middleware easier.
Example:
apiVersion: "1.0.0"
basePath: "http://blah.com/api/1/"
swaggerVersion: "1.2"
resourcePath: /apps
apis:
- path: /apps
swagger-metadata is creating the path regexps properly but when it goes to find one that matches the current path (swagger-megadata.js line 98) it doesn't take the basePath into account.
I think the best bet is to strip the path portion of basePath before doing the find() so I'm going to try that.
We need to make sure we identify operation parameters with the same name
and type
as errors.
Hello,
We have an express app built form a127-magic which I'm trying to add the swaggerUI middleware.
Here is some of the related code in app.js
var a127 = require('a127-magic');
var a127Config = a127.config.load();
var a127Magic = a127Config['a127.magic'];
var swaggerTools = require('swagger-tools').middleware.v2_0;
app.use(swaggerTools.swaggerUi(a127Magic.swaggerObject));
The url http://localhost:10010/api-docs works great returning the JSON.
http://localhost:10010/docs has several console message:
no zlib library
no iconv library
no group to bind to (this occurs several times)
Then the following http://monosnap.com/image/ikQNydIKa4MjNHsymAfNyRAdWV2sxz.png
The UI never loads. Everything else works great.
It would be nice to be able to take Swagger 1.2 documents and convert the to Swagger 2.0 documents.
Currently, when there is a validation error in the request, a 500 Internal Server Error
response is returned.
This seems a little odd, since a malformed request should return a 400 Bad Request
response, as stated in this RFC.
It would be nice to allow swagger-router handlers to know if mock mode is enabled or not so the controller can return a real response or a mock response based on this flag.
First reported here: http://community.apigee.com/questions/309/a127-swagger-editor-parameters-type-file.html#answer-311.
The simplest case I can make is to put this in the paths section:
/upload:
post:
consumes:
- multipart/form-data
parameters:
- name: myFile
in: formData
type: file
responses:
"200":
description: response
As far as I can tell from the spec, this should be valid but it gets a validator error:
swaggerError: ValidationError
message: "Data does not match any schemas from "oneOf""
code: 11
dataPath: "/paths/~1upload/post/parameters/0"
schemaPath: "/properties/paths/patternProperties/^~1$|^~1.*[^~1]$/properties/post/properties/parameters/items/oneOf"
I have begun experimenting with swagger and swagger-tools has been an obvious choice but i am a bit confused about some valid JSON schema elements not being honored by the swagger validator.
To take the weather example , I wanted to add a 'pattern' to the 'location' parameter stating it must follow a specific pattern, so i added pattern to the location parameter
"parameters": [
{
"name": "location",
"in": "query",
"description": "The MSN Weather location search string.",
"required": true,
"type": "string",
"pattern":"validPattern"
}
]
Swagger spec says this should be possible, but the swagger tools validator says
Can someone please explain whats going on here because i have seen this happen for other properties as well.
v1.2 JSON schema for API Declaration's authorizations
property is wrong and it impacts validation. Here is the referenced bug: reverb/swagger-spec/issues/118
Issue #49 was a result of swagger-ui not being updated to support changes to the 2.0 schema file. We need to have a test suite that ensures that swagger-ui is working properly.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.