swagger-tools icon indicating copy to clipboard operation
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.

Open mlitwin opened this issue 7 years ago • 12 comments

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.

mlitwin avatar Mar 17 '17 04:03 mlitwin

I'll take a peek.

whitlockjc avatar Mar 17 '17 15:03 whitlockjc

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;

mlitwin avatar Mar 17 '17 16:03 mlitwin

@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 ;)

mlitwin avatar Mar 27 '17 04:03 mlitwin

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.

whitlockjc avatar Mar 27 '17 18:03 whitlockjc

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.

diversario avatar May 02 '17 20:05 diversario

Thanks for the heads up. I'll be on it soon.

whitlockjc avatar May 02 '17 20:05 whitlockjc

In the meantime, is there a way to tell swagger that any type is valid as item type?

diversario avatar May 02 '17 21:05 diversario

Ok, this works

      "type": "array",
      "items": {}

diversario avatar May 02 '17 21:05 diversario

That was going to be my answer. ;)

whitlockjc avatar May 02 '17 21:05 whitlockjc

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...

janjilek avatar Sep 11 '17 11:09 janjilek

+1

cbayram avatar Jan 03 '18 22:01 cbayram

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. image

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 image

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

image

and will replace schema with {} (object)

then, it will reach the case object block image

which will try to run JSON.parse on the string. for every string, it will be ok, as JSON.parse will return error,

image

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,

image

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!

ET-CS avatar Jan 17 '21 21:01 ET-CS