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.
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.
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]
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.
Most helpful comment
I can reproduce the problem. The root cause is that we cache AJV validators but the
optionsis not taken into consideration. The json body does not require coercion while urlencoded body requires. As a result, the cached AJV validator does not supportcoercionif it's used first.I'll look into a fix tomorrow.