Python version 3.6.5
Connexion Version 2.2.0
OpenAPI 3 Spec.
I'm trying to do simple requestBody Validation, it does not give proper error detail.
{
"detail": "None is not of type 'object'", // When sending an empty json body.
"status": 400,
"title": "Bad Request",
"type": "about:blank"
}
Also the error messages are very vague at property level too, it does not give the exact property name, any idea why?
{
"detail": "'' is too short'", // The property name is 'xyz' type string and length is 3
"status": 400,
"title": "Bad Request",
"type": "about:blank"
}
Is this a regression?
@dtkav any thoughts on this?
Hey @peek4y
Please attach a spec, and a curl command that reproduces the issue.
I'm unable to reproduce the issue with the information you have provided.
The spec config.
openapi: 3.0.0
info:
title: Sample
version: "1.0"
paths:
/users:
post:
summary: Adds a new user
operationId: app.postUser
requestBody:
required: true
content:
application/json: # Media type
schema: # Request body contents
$ref: "#/components/schemas/User" # Reference to an object
example: # Child of media type because we use $ref above
# Properties of a referenced object
id: 10
name: Jessica Smith
responses:
"200":
description: OK
components:
schemas:
User: # Schema name
type: object
properties:
id:
type: integer
format: int64
example: 1 # Property example
name:
type: string
minLength: 3
example: New order
required:
- id
- name
Validating empty body:
curl -X POST "http://localhost:8080/users" -H "accept: */*" -H "Content-Type: application/json"{
"detail": "None is not of type 'object'",
"status": 400,
"title": "Bad Request",
"type": "about:blank"
}Validating type:
curl -X POST "http://localhost:8080/users" -H "accept: */*" -H "Content-Type: application/json" -d "{\"id\":\"1\",\"name\":\"Evee\"}"{
"detail": "'1' is not of type 'integer'",
"status": 400,
"title": "Bad Request",
"type": "about:blank"
}curl -X POST "http://localhost:8080/users" -H "accept: */*" -H "Content-Type: application/json" -d "{\"id\":1,\"name\":\"Ee\"}"{
"detail": "'Ee' is too short",
"status": 400,
"title": "Bad Request",
"type": "about:blank"
}@dtkav hey, just wondering if you got a chance to look at this, were you able to reproduce it?
Regarding the empty body, the message is exactly what I would expect it to be.
You have specified that the type of the body must be an object but you have passed null.
Regarding the property validation, I agree it would be nice if the field was mentioned.
Reading through the jsonschema docs, this should be relatively straightforward.
There's a PR that was started to address this issue: https://github.com/zalando/connexion/pull/816
Unfortunately, it needs a bit more work before it's ready to be merged.
I'd encourage you to pick it up and run with it if you have available bandwidth.
I'd be happy to review a pr, and recommend it for merge by folks at zalando once it's up to standards.
@dtkav
Regarding the null / empty body part, I agree with your point, but then I would still expect a readable message, IMO, maybe it's a nice to have?
Sure, I will take a shot at it, soon, and go through the PR as well.
Thanks a lot for the response!
I think it would be good to clean this up. The "None is not of type 'object'" may be clear to a server developer, but it doesn't make much sense to someone who's writing an API client. Connexion should either treat an empty request body the same way as {}, or return an error message that tells the client that the request body is required.
Connexion should either treat an empty request body the same way as {}
We definitely do not want to to this. A null body, and an empty json object are entirely different things.
Perhaps fixing #878 (support requestBody: required) will also address this concern.
That way, if we mark the request body as required, then the error message would be something like "requestBody is required".
Yep, that would work. Thanks for following up on this! I didn't know about the required field on requestBody until today.
We had a similar problem - this might help.
Creating a validators.py module that looks like this.
"""
This module contains custom validators
that override the default connexion behaviour.
"""
import logging
from connexion.problem import problem
from connexion import decorators
from jsonschema import ValidationError
logger = logging.getLogger("connexion.decorators.validation")
class RequestBodyValidator(decorators.validation.RequestBodyValidator):
"""
This class overrides the default connexion RequestBodyValidator
so that it returns the complete string representation of the
error, rather than just returning the error message.
For more information:
- https://github.com/zalando/connexion/issues/558
- https://connexion.readthedocs.io/en/latest/request.html
"""
def validate_schema(self, data, url):
if self.is_null_value_valid and is_null(data):
return None
try:
self.validator.validate(data)
except ValidationError as exception:
logger.error(
"{url} validation error: {error}".format(url=url, error=exception),
extra={"validator": "body"},
)
return problem(400, "Bad Request", str(exception))
return None
In your app.py overwrite the default RequestBodyValidator as follows:
from validators import RequestBodyValidator
# ...
app.add_api(
"app.yml",
validator_map={"body": RequestBodyValidator},
)
Most helpful comment
We had a similar problem - this might help.
Creating a
validators.pymodule that looks like this.In your
app.pyoverwrite the defaultRequestBodyValidatoras follows: