Currently, we have separate errors field rather than using already existing error feature provided by graphene.
~https://github.com/graphql-python/graphene-django/blob/master/graphene_django/rest_framework/mutation.py#L77~
https://github.com/graphql-python/graphene-django/blob/master/graphene_django/rest_framework/mutation.py#L128
So instead we could simply raise the ValidationError raised by serializer, and let graphene handle it.
mmh, I'm not sure this is something we want. I usually treat the graphene errors as something that's not fixable by the end user. But that's my personal preference, also because graphql errors are a bit limited.
I'm up for suggestions here, @syrusakbary @spockNinja
I agree with @patrick91. I believe the error fields on the SerializerMutation are quite intentionally separate from GraphQL errors. These are generally field-level validation errors and will not only have a different structure from normal errors, but are handled differently by the client.
For example, getting a GraphQL query syntax error is not your end-user's fault, and should be handled by a developer before you get into production. However, the "errors" on the SerializerMutation will happen all the time in production and should be passed on to your end user so that they can fix the data in their form and try again.
Makes sense. Thanks for feedback.
I have just bumped into the same issue and first thought this is a bug before I have encountered this issue.
I think this decision should be reconsidered, let me outline why:
Reference for status codes: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
What do you think?
I am happy to work on a PR if we can agree that this should be adjusted.
I just got tripped up on this as well @sliverc. I had to read through the SerializerMutation source code to figure out what was happening.
@sliverc @charlex I see your point, but I'm not sure how we should manage errors, would something like this work?
{
"errors": [
{
"message": "Validation failed.",
"locations": [ { "line": 6, "column": 7 } ],
"path": [ "createHero" ],
"extensions": {
"fieldErrors": {
"name": ["This field cannot be empty"]
},
"timestamp": "Fri Feb 9 14:33:09 UTC 2018"
}
}
]
}
GraphQL errors encode exceptional scenarios - like a service being down or some other internal failure. Errors which are part of the API domain should be captured within that domain.
I am a bit confused by this statement in the related issue as the specification doesn't explicitly state that this is the case (at least that's how I read it).
The specification rather states:
If the result of resolving a field is null (either because the function to resolve the field returned null or because an error occurred), and that field is of a Non-Null type, then a field error is thrown. The error must be added to the "errors" list in the response.
Trying to rephrase this for our case:
Each field returned by mutation which is null because of an error should have an error in errors.
Hence I suggest Graphene Django adds one error for each validation exception. This might need changes on graphql-core as well? The way how you have suggested would also be a good first step to move forward.
Also such a change depends on a fix for issue https://github.com/graphql-python/graphql-core/issues/203
All in all changing this won't be trivial as changes in graphql-core are most likely necessary. But could we still reopen this issue? This way users with the same issue will find it better as the discussion continues. And as stated when we agree on a solution I am open to help with a PR if needed.
@sliverc sorry I missed your reply! Thank you @annshress for reopening this!
I'm honestly a bit conflicted between the various option, I was actually writing a blog post about dealing with user errors in GraphQL. My main reason to have errors in the schema is that they are typed[1], so they super easy to use (especially if you want to show them inline with the fields).
Unfortunately, I've seen people misusing these errors and not actually requesting them when doing mutations, so I was thinking of other approaches for handling them, and from what I've seen there are 3 options:
A. Errors in GraphQL, I like it, but they can be easily ignored by devs (happens a lot, unfortunately) but also they are not typed (I'm not sure having extensions will help us here)
B. Errors as fields like we have now (but typed better) same here, it is really easy to not request the field errors or miss a single field. But they are typed
C. Return a union type for the mutation, so when using the mutation and its return type we would need to add a check for the type, this basically adds a hint to the developers that they have to fetch the errors, but even here it is easy to miss a field.
Example for option A:
mutation {
createUser(name: "example") {
user {
name
}
}
}
Here there's no need to request for the errors, they would be all passed into the error field of the response.
Example for option B:
mutation {
createUser(name: "example") {
user {
name
}
errors {
name
nonFieldErrors
}
}
}
Here we have to fetch the errors by field (including nonFieldErrors), again this is quite easy to miss
Example for option C:
mutation {
createUser(name: "example") {
... on User {
name
}
... on CreateUserErrors {
name
nonFieldErrors
}
}
}
Here we need to handle the union type, this kinda forces us to check the errors but you could still miss a field.
I'm working on a PR to improve Form and Serializer mutations, and I might include a new error handling, I'm honestly thinking of implementing all 3 solutions and let whoever is using the library which one they prefer, I'll keep you posted :)
[1] Graphene Django Mutation is not nicely typed but that's another issue
@patrick91 Thanks for your feedback and working on this. Providing all three options might be a way forward.
Personally I think though this is rather a matter of what the specification states and not what we prefer to do in graphene. Maybe this needs to be raised again within context of graphql specification as it seems the specification is not clear at this point.
I've run into this today in terms of handling errors in my application. I have been creating Union types between Nodes and Errors so I can return DRF validation errors.
I'm hooking this up to an apollo-client which thinks because the request has 200 response everything is fine. However, there is a validation errors in the data key. For now I'm making the client check the data key for errors.
It'd be great if there was a way to reduce the tedium and have something that produces errors into a single field.
@patrick91 for option A how will we handle multiple validation errors? The graphql.error.GraphQLError only encapsulates a single instance of an error. DRF's validation errors are an array with multiple messages. It'd be great if we didn't lose that existing functionality.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I am facing an issue maybe similar to this one?
I am using model serializer in serializermutation which relies on models' field attributes null=True to determine whether a field is required. This is normally fine for most operation except delete, in which requires me to enter data for all required field when only id is needed.
We really need a way to fix this.
`{
"errors": [
{
"message": "Argument \"input\" has invalid value {id: \"V_cX1txRTVaMI0jDu5uoaQ\"}.\nIn field \"type\": Expected \"String!\", found null.\nIn field \"suffix\": Expected \"String!\", found null.\nIn field \"mime\": Expected \"String!\", found null.",
}
]
}`
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
is there any update on this issue?
we would like to standardize our mutations so that there is no need to specify/select "errors" .. it should be there by default if there is an error.
@patrick91 I believe that you ware working on a PR that address this issue, I am not sure what is that status.
By the way, here is what Apollo server does: https://www.apollographql.com/docs/apollo-server/data/errors/#augmenting-error-details
@patrick91 is it okay with we re-open and prevent the stale bot from closing?
I'll reopen this issue for more discussion but IMO expected errors (like validation errors) should be modelled in the schema. The top level errors key is reserved for unexpected server errors and that seems to be official position from the GraphQL spec as well: https://github.com/graphql/graphql-spec/issues/391#issuecomment-385553207
Most helpful comment
I have just bumped into the same issue and first thought this is a bug before I have encountered this issue.
I think this decision should be reconsidered, let me outline why:
Reference for status codes: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
What do you think?
I am happy to work on a PR if we can agree that this should be adjusted.