-
Notifications
You must be signed in to change notification settings - Fork 301
support nested structures #776
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
Conversation
@sliverc Hi. I made PR we discussed here #769 UPD: UPD 2: |
Update my fork
# Conflicts: # rest_framework_json_api/renderers.py
Codecov Report
@@ Coverage Diff @@
## master #776 +/- ##
==========================================
+ Coverage 97.32% 97.36% +0.03%
==========================================
Files 56 56
Lines 2920 2962 +42
==========================================
+ Hits 2842 2884 +42
Misses 78 78
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about increasing the coverage? & are you sure this is compliant with 1.0 or 1.1 specs of json-api?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you check the build failures?
@auvipy Yeah, I have checked. I really messed up. Btw, don't merge this pr, I found out that there is an issue with error object generation, which I will resolve on Thursday. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this. See my inline comments. For error object object generation when looking through the code it is not totally obvious what causes this but hope you can tackle that issue as well.
…hat DeprecationWarning raises whenever nested serializer is used without correct settings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your updates. The PR is shaping up nicely - good work so far! There are some comments I have added though.
rest_framework_json_api/utils.py
Outdated
# handle all errors thrown from serializers | ||
else: | ||
for field, error in response.data.items(): | ||
field = format_value(field) | ||
pointer = '/data/attributes/{}'.format(field) | ||
# see if they passed a dictionary to ValidationError manually | ||
# The bit tricky problem is here. It is may be nested drf thing in format | ||
# name: error_object, or it may be custom error thrown by user. I guess, | ||
# if it is drf error, dict will always have single key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is not quite clear what is happening here. Can you elaborate on this issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the record, all of this needed to put the correct pointer into an error object.
Well, the issue here is that the error
object may be any valid dict with any string as a key and any object as a value.
Let consider two examples. First one is validator method in identity serializer
As you can see users can specify any dict whatever they want as a detailed message, and old behavior would be "pass it as is, do nothing". By the way, I am not entirely sure that old behavior is correct and we still should pass this object as is. At least we have to append pointer here if it is possible.
The second example is second level attribute exception
In this case, an error object will be
{
"body": ["This field is required"]
}
where the body is a field name. Moreover, if we consider a more deep nested structure, the error object will be more complicated with nested dicts and lists. This is just how DRF validation works and passes errors.
But I am quite sure if we get a single dict DRF error it will be always a dict with a single key consists of field name and either error message, dict or list depending on the serializer field type.
Since we don't know from where the error object come out neither we don't know serializer structure at this point it is a tricky question how we can separate custom error object defined by users from that errors generated by DRF itself. I assumed this heuristic with a length of the dict is the simplest solution, even though it doesn't feel entirely correct.
The other possible solutions are:
-
Overwrite serializer's validation process and extend the validation error class so we can put the correct pointer at the moment we get an error. I assume this is the most correct way to deal with these problems. However, it will take too much effort and I am not able to do that in the nearest future.
-
The spec states:
An error object MAY have the following members:
id
: a unique identifier for this particular occurrence of the problem.
links
: a links object containing the following members:
about: a link that leads to further details about this particular occurrence of the problem.
status: the HTTP status code applicable to this problem, expressed as a string value.
code: an application-specific error code, expressed as a string value.
title
: a short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization.
detail
: a human-readable explanation specific to this occurrence of the problem. Like title, this field’s value can be localized.
source
: an object containing references to the source of the error, optionally including any of the following members:
pointer
: a JSON Pointer [RFC6901] to the associated entity in the request document [e.g. "/data" for a primary data object, or "/data/attributes/title" for a specific attribute].
parameter: a string indicating which URI query parameter caused the error.
meta
: a meta object containing non-standard meta-information about the error.
We can come up with another heuristic to check that if dict contains any subset of these fields. However it doesn't protect us in two problems: first, these fields may overlap with serializer fields and second, users may pass as a dict key whatever they want which may be neither serializer field or spec stated field.
I am not sure what we should do with this comment, I can expand it with detailed explanation copy-pasted from here with todo inserted or leave it as is with the issue reported.
I would prefer to report this to the doc as a known issue and merge this pr as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a night with an idea of overwriting the validation process, I don't think it entirely solves this problem. We would still get all of this problems in case a user uses plain drf serializers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From a JSON API specification perspective the nested json is actually just a value and it suggests that an error is reported on an JSON API attribute level.
As we are having some issues concerning this would it not be better that we simply report an error on the attribute level and not on the nested value? I have a feeling this would also follow the spec closer although it doesn't seem to forbid to do more nested errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sliverc
I am not sure.
In my opinion, JSON:API spec is quite strict about what exactly pointer attribute must contain
pointer
: a JSON Pointer [RFC6901] to the associated entity in the request document [e.g. "/data" for a primary data object, or "/data/attributes/title" for a specific attribute].
So if we have an error somewhere deep in a nested structure, but we report it as it would happen in top-level attribute, it just doesn't feel correct and seems to be out of spec.
Moreover, it is not clear what exactly we have to put into the detail
field. We aren't seem permitted to put here JSON object, detail
has to be string, as far as I understand. If we will try to extract this string from the depth of the error object, we would fail into the same problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, I want to know should we inject the source
object into the custom error object or not? I think It would be nice if we persist one if the error object doesn't have it already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great that we have access to the serializer. In case of injecting of the source object. Yes that would be good, but only if it doesn't already exist. It is kind of blowing up this PR though. Our main issue at this point is error handling and the rest would be mergeable in this PR. So what do you think if we move the part of error handling into a second PR and merge this PR? In the second PR injecting source could also be part.
We won't release before this second PR would have been landed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that sounds reasonable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sapiosexual Could you extract the error handling part from this PR into a new then? Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great job
Fixes #769
Description of the Change
Checklist
CHANGELOG.md
updated (only for user relevant changes)AUTHORS