-
-
Notifications
You must be signed in to change notification settings - Fork 456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ValidationError includes other keys apart from the actual key #143
Comments
Hi @blazing-gig can you show your operation definition ? @api.post(...
def operation(request, ... |
Hey @vitalik , Here's the api def @org_api_router.post('/')
def org_create_view(request, org: OrgSchemaIn):
created_org = Org.objects.create(**org.dict())
return CustomResponseObj(
status=StatusConstants.SUCCESS,
data=OrgSchemaOut.from_orm(created_org)
).dict() |
Am on the same page with you @blazing-gig
from this validation
with this router
from this I can know that on the request "body", "payload" is the one reference on "loc" Have tried this
but it override all errors with one single message Have tried to modify my custom validator to this
and the error representation changed to this
but the problem pydantic default validation is not changing which make confusing on error representation |
I think the misunderstanding here is that
it' just enough to do assert with a message: @validator("truck_plate_number")
# unique plate number for either a truck or tank
def unique_plate_number(cls, v):
exist = Vehicle.objects.filter(Q(truck_plate_number=v)).exists()
assert not exist, "plate number is in use" # <-----
return v
Note: you will never catch pydantic.ValidationError in and indeed these new details also has information about operation argument that was not able to validate (like body.org or body.payload your respective cases) It is there so that in your exception_handler you can understand which model raised validation error for both your cases I guess if you want to skip variable in your http response you can do the following : from ninja.errors import ValidationError # not pydantic !!!
@api.exception_handler(ValidationError)
def validation_errors(request, exc):
for err in exc.errors:
err["loc"] = [err["loc"][0], err["loc"][-1]] # skip argument <------- !!
return api.create_response(request, {"detail": errors}, status=422) |
I can skip overriding
|
for 404 you can use django's get_object_or_404 from django.shortcuts import get_object_or_404
...
def update_vehicle(request, truck_id: int, payload: VehicleUpdateSchema):
truck = get_object_or_404(Vehicle., id=truck_id)) # <---- this will throw default 404 JSON response (that you can overrie)
data = payload.dict()
data["created_by"] = request.user
for attr, values in data.items():
setattr(truck, attr, values)
.. |
Hey @vitalik Firstly, thanks for responding. I already had in mind the technique which you mentioned about handling The only problem I face here is that 99% of the time, I'd just like to directly return the On the other hand, I do agree that this info might come in handy if the api is doing some kind of request logging and needs to identify the source of the error. To take a mean path, would it be possible for a switch to be exposed at the api = NinjaAPI(..., validation_err_with_ctx=True/False)
# the same can be overridden at the router and api level Another approach could be to take a custom class that can subclass # the dotted path to this class can be gotten from `settings.py` or anywhere else and imported at runtime.
class CustomValidationError(ninja.ValidationError):
inject_request_context = True / False Let me know your thoughts on the same. Also, I made a comment on one of the open proposals as well. Feel free to check it out. |
Hey @vitalik , Any update on this ? Just trying to keep the discussion alive. |
still thinking... maybe the exception will contain references to original exception... but on the other hand it's almost identical except this patch
|
Hey @vitalik , I understand your confusion. So I believe there are two paths here that can potentially be taken:
Based on the above, I feel going for the reference to the original exception is a safer bet. Let me know your thoughts on the same. |
but i'm not yet sure how reference will improve here... let's take a case like this: class Payload(Schema):
x: int
y: int
@api.post('/task/{id}')
def do_some_with_task(request, id: int, payload: Payload):
pass now imagine you are posing invalid request where id is not integer and x is missing:
this will result that will contain two errors:
I mean you already have all the information and can report to the client this response or patch it and report your own |
Hey @vitalik , Thanks again for responding. I see what you're saying. Let me give it a short think and get back. |
I guess if you only intereseted in last attribute you can just patch loc with deatais['loc'] = [deatais['loc'][-1]] |
Here is a simple helper function that can be used to parse the errors into a json on the form:
And then override:
Works like a charm |
Totally agree @blazing-gig that The second item, Though, if a view have two body arguments, like the following example, then they should be part of @api_router.post('/')
def foobar(request, a: SchemaA, b: SchemaB):
... ... since in this case the client would actually post data on fields About the first item in loc,
To solve this here, I think this might be the place to craft Thoughts or better placed fix @vitalik ? |
Hey @vitalik ,
Something that I noticed with the
ValidationError
being thrown is that there are additional fields present as opposed to the fields that are expected if the sameValidationError
gets thrown from pydantic. The major problem with this is that when the client has to map this data to display the error to the user, it has to deliberately strip away a few fields all the time which doesn't make sense.For eg:
The
ValidationError
that django-ninja gives for an invalid input:The
ValidationError
that Pydantic gives for invalid input:The latter is the one I expect django-ninja to return as well. I'd like to know your thoughts on this.
The text was updated successfully, but these errors were encountered: