Loopback-next: Multiple content types in requestBody problem

Created on 25 Jun 2019  ·  1Comment  ·  Source: strongloop/loopback-next

Steps to reproduce

With a simple model Product

@model({settings: {}})
export class Product extends Entity {
  @property({
    type: 'number',
    id: true,
    required: true,
  })
  id: number;

  @property({
    type: 'string',
    required: true,
  })
  name: string;

  constructor(data?: Partial<Product>) {
    super(data);
  }
}

and controller operation with @requestBody has application/x-www-form-urlencoded and application/json as content types

@post('/products')
ping(
  @requestBody({
    content: {
      'application/x-www-form-urlencoded': {},
      'application/json': {},
    },
  })
  product: Product,
): object {
  return {product};
}

Send request with Content-Type: application/json

curl -X POST \
  http://localhost:3000/products \
  -H 'Content-Type: application/json' \
  -d '{"id": 10, "name": "Simple product"}'

And then send request with Content-Type: application/x-www-form-urlencoded

curl -X POST \
  http://localhost:3000/products \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'id=15&name=Simple%20product'

The bug appears (UnprocessableEntityError).

Stop the app and start it again and reverse requests, First send request with Content-Type: application/x-www-form-urlencoded and then send request with Content-Type: application/json, The bug disappears.

Current Behavior

When we have an operation with multiple content types (application/x-www-form-urlencoded and application/json)
If we send request with Content-Type: application/json and then send request with Content-Type: application/x-www-form-urlencoded we get UnprocessableEntityError

{
    "error": {
        "statusCode": 422,
        "name": "UnprocessableEntityError",
        "message": "The request body is invalid. See error object `details` property for more info.",
        "code": "VALIDATION_FAILED",
        "details": [
            {
                "path": ".id",
                "code": "type",
                "message": "should be number",
                "info": {
                    "type": "number"
                }
            }
        ]
    }
}

But if we reverse requests we don't get this problem.

Additional information

linux x64 10.16.0
[email protected] /home/amr/Desktop/loopback-app
├── @loopback/[email protected]
├── @loopback/[email protected]
├── @loopback/[email protected]
├── @loopback/[email protected]
├── @loopback/[email protected]
├── @loopback/[email protected]
├── @loopback/[email protected]
├── @loopback/[email protected]
├── [email protected]

2019Q3 REST Validation bug

Most helpful comment

I can reproduce the problem. The root cause is that we cache AJV validators but the options is not taken into consideration. The json body does not require coercion while urlencoded body requires. As a result, the cached AJV validator does not support coercion if it's used first.

I'll look into a fix tomorrow.

>All comments

I can reproduce the problem. The root cause is that we cache AJV validators but the options is not taken into consideration. The json body does not require coercion while urlencoded body requires. As a result, the cached AJV validator does not support coercion if it's used first.

I'll look into a fix tomorrow.

Was this page helpful?
0 / 5 - 0 ratings