swagger-tools
swagger-tools copied to clipboard
For a POST with body taking an array of strings, elements of the array can be improperly coerced into numeric values.
So with schema like:
/vocabulary: post: operationId: "vocabularyPOST" produces: - "application/json" parameters: - $ref: "#/parameters/vocabBody"
.... vocabBody: in: "body" name: "body" description: "JSON array of term codes." required: true schema: $ref: "#/definitions/termCodeList" ... termCode: type: "string" termCodeList: type: "array" items: $ref: "#/definitions/termCode"
A POST with body ["1"] will fail validation. Internally it seems that the "1" is coerced into an integer, and then the array [1] fails validation.
If I'm understanding the code, the issue is at https://github.com/apigee-127/swagger-tools/blob/master/middleware/helpers.js#L231 where schema can (if it's a request parameter?) need to be dereferenced to schema.schema. Something similar seems to be happening at https://github.com/apigee-127/swagger-tools/blob/master/middleware/helpers.js#L43
But I've not traced it all the way down.
I'll take a peek.
Great! Looking at it more closely, I think any string in the array that's valid JSON with be JSON.parse()ed.
Workaround I am thinking about in helpers.js:
- var iSchema = _.isArray(schema.items) ? schema.items[index] : schema.items;
+ // Apparent bug: schema for a parameter is one level down from the passed in schema
+ // so iSchema will be undefined, resulting in unwanted conversions.
+ // something like this was already being done in getParameterType() q.v.
+ var tSchema = schema.schema ? schema.schema : schema;
+ var iSchema = _.isArray(tSchema.items) ? tSchema.items[index] : tSchema.items;
@whitlockjc does my workaround seem reasonable? I'd like to land a fix in my own local copy of swagger-tools, at least, but would feel better about it if made sense to you ;)
I think we just need to avoid using JSON.parse
on items whenever we're coercing them if the type is string
. That would be the ideal solution.
This also affects responses. Given this response definition
"type": "array",
"items": {
"type": "string"
}
and this response
[ '1a', '2b', '3c', '4d', '5e', '987123E456' ]
Swagger errors out with
code: "INVALID_TYPE",
message: "Expected type string but found type unknown-number",
path: [
"5"
]
This is because the string "987123E456"
can be parsed into a valid JS number. This is a production-breaking bug for my application right now.
Thanks for the heads up. I'll be on it soon.
In the meantime, is there a way to tell swagger that any type is valid as item type?
Ok, this works
"type": "array",
"items": {}
That was going to be my answer. ;)
Any news? It's really annoying bug and it's breaking my production env when sending twitter ids. It's just parsed in the wrong way and I am getting different number...
+1
Hi.
We experienced this too in production.
Our swagger.yml
file consisting something like:
swagger: '2.0'
paths:
'/v1/some/api':
post:
summary: ...
operationId: ...
consumes:
- application/json
produces:
- application/json
parameters:
- name: collectionIds
in: body
description: 'Collections to retrieve'
required: true
schema:
type: array
items:
type: string
for every array of collectionIds
it was passing correctly (or did it?) but for the following body ['60000528880e130012727947']
is started returning an error:
Request validation failed: Parameter (collectionIds) failed schema validation",
"errors": [
{
"code": "INVALID_TYPE",
"message": "Expected type string but found type unknown-number",
"path": [
"0"
]
}
]
Debugging this project, seems the the issue is swagger-validator.js
file, inside the validateValue
function.
In case of an array, when this line is triggering:
val = mHelpers.convertValue(val, schema, mHelpers.getParameterType(schema), location);
it will reach this block inside convertValue
which will recursive call itself
and iSchema
will be for some reason undefined
, so it will call convertValue
with second and third param of undefined for the items inside the string.
so, convertValue
will get the schema
and type
params with undefined
values
and will replace schema
with {}
(object)
then, it will reach the case object
block
which will try to run JSON.parse
on the string.
for every string, it will be ok, as JSON.parse
will return error,
and then the convertValue
function will return the original
value which can then be validated against string
correctly,
but in our special case, the id
was containing only numbers with one 'e' char in the middle...
so JSON.parse consider this string as e-notation number . the exponent, 130012727947, is too large to fit into a 64-bit floating pointing, so it defaults to Infinity,
which then ofcourse can't be validated against string.
for now, we used @diversario solution and replaced the validation with
"type": "array",
"items": {}
but it's not really a solution as we lost the string validation(?).
is there anything we can fix in our swagger.yml
file to have convertValue
detect iSchema.type
correctly as string
?
or is this a bug in the code?
Thanks in advance for this helpful project!