Skip to content

Document how to customize global, request validation errors that prevent execution #487

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

Closed
christianrowlands opened this issue Sep 14, 2022 · 5 comments
Assignees
Labels
type: documentation A documentation task
Milestone

Comments

@christianrowlands
Copy link

christianrowlands commented Sep 14, 2022

I apologize if I missed it, but I did a scrub of the documentation and I could not find anything about how to handle returning custom responses for request that don't pass schema validation.

Right now, I am seeing something like the following returned from this framework:

{
    "errors": [
        {
            "message": "Variable 'myVariable' has an invalid value: Field 'name' has coerced Null value for NonNull type 'String!'",
            "locations": [
                {
                    "line": 1,
                    "column": 21
                }
            ],
            "extensions": {
                "classification": "ValidationError"
            }
        }
    ]
}

This does provide the relevant information for someone experienced with GraphQL because it mentioned the field name is a String!. However, I would like to return a simplified message such as "The name field is required in the MyInputObject when making the mutation someMutationCall", or something like that.

I poked around the code base a bit and found that the org.springframework.graphql.execution.DefaultExecutionGraphQlService class has an execute method. If I create my own implementation and register it as a bean I see that the execute method is called and there I can transform the above error into something more beginner developer friendly.

There are two problems with the above approach. First, the DefaultExecutionGraphQlService#execute method is final, so I can't just override it, I have to create a whole new custom implementation of the interface. Second, I don't really like handling this in the execute method. Instead, I really like the approach that was taken with the DataFetcherExceptionResolverAdapter where we can just override the com.opengov.coa.definition.adapter.http.errors.CoaDefinitionErrorHandler#resolveToMultipleErrors method. It would be great if there was something similar to that for validation of the request.

I did find this existing ticket, but it is a bit different.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 14, 2022
@rstoyanchev
Copy link
Contributor

DefaultExecutionGraphQlService is mainly for framework use and should also be marked final as a class. The interception chain in front of it is meant to provide hooks for the HTTP request and response, the GraphQL engine ExecutionInput and ExecutionResult.

In an interceptor, WebGraphQlResponse exposes the ExecutionResult. A result with errors only and no data is a global, request error that happens prior to execution. You can re-create the ExecutionResult, perhaps with ExecutionResultImpl.newExecutionResult().from(executionResult)... and then use WebGraphQlResponse#transform to replace the ExecutionResult.

We can expand the reference docs a bit with this use case in mind.

@rstoyanchev rstoyanchev added type: documentation A documentation task and removed status: waiting-for-triage An issue we've not yet triaged labels Sep 15, 2022
@rstoyanchev rstoyanchev added this to the 1.0.2 milestone Sep 15, 2022
@rstoyanchev rstoyanchev changed the title Custom Request Validation Error Responses Document how to customize global, request validation errors that prevent execution Sep 15, 2022
@christianrowlands
Copy link
Author

I appreciate the quick response! That sounds like it should work nicely. I will give that a go and report any problems or use cases that it does not cover. Thanks!

@rstoyanchev rstoyanchev self-assigned this Sep 15, 2022
rstoyanchev added a commit that referenced this issue Sep 16, 2022
@christianrowlands
Copy link
Author

I took a stab at using this approach. It mostly works, but I run into a problem where I don't have the information I need to create a good error message. For example, in the GraphQlError that I can get in the intercept method, I don't have access to the field name that is missing or invalid. I worked up a solution that parses the exception's message to extract the field name from there, but when testing that change it appears the field name can show up in a variety of ways depending on the GraphQL call. Parsing the error message is a hack anyway so it is not ideal.

Is there a way to get the field name that is missing or invalid in the intercept method?

@rstoyanchev
Copy link
Contributor

rstoyanchev commented Sep 19, 2022

I think this is more of a GraphQL Java question now. You might want to ask there for further options. Feel free to comment here later with more information or a link to an external discussion.

@christianrowlands
Copy link
Author

That makes sense.

I created a ticket: graphql-java/graphql-java#2964

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation A documentation task
Projects
None yet
Development

No branches or pull requests

3 participants