[FIXED] GraphQL Spring Boot Web Interceptor to return an error response if headers not present

Issue

I’m trying to create logic that will intercept all /graphql requests, check if headers are present and add them to MDC, and if not "reject" the request with an appropriate error.

First attempt was to add it to a registered AsyncHandlerInterceptor#preHandle, where I threw an IllegalArgumentException. Unfortunately, the DataFetcherExceptionResolverAdapter does not pick it up.
Then I tried a a WebInterceptor, but again the resolver doesn’t see this exception.

Here is the interceptor, I’m very new to reactive, so pls don’t judge lol.
It seems to work correctly, when the header is present, but not when the exception is thrown.

@Bean
public WebInterceptor headerInterceptor() {
    return (webInput, chain) ->
        chain.next(webInput)
            .doFirst(() -> {
                String header = webInput.getHeaders().getFirst("some-header");
                if (header != null && !header.isEmpty()) {
                    MDC.put("some-header", header);
                } else throw new IllegalArgumentException("...");
            })
            .doFinally(s -> MDC.clear());
}

Interceptor code (not reached):

public class SomeDataFetcherExceptionResolverAdapter extends DataFetcherExceptionResolverAdapter {

    @Override
    protected GraphQLError resolveToSingleError(Throwable throwable, DataFetchingEnvironment environment) {
        if (throwable instanceof ConstraintViolationException || throwable instanceof IllegalArgumentException) {
            return GraphqlErrorBuilder
                    .newError(environment)
                    .errorType(BAD_REQUEST)
                    .message(throwable.getMessage())
                    .build();
        } else {
            return super.resolveToSingleError(throwable, environment);
        }
    }
}

Solution

Here’s what I ended up doing:

public class GraphqlHeaderInterceptor implements WebInterceptor {
...
    @Override
    public Mono<WebOutput> intercept(WebInput input, WebInterceptorChain chain) {
        return chain.next(input)
                .doFirst(() -> {
                     // fill MDC or throw Exception if no header
                })
                .onErrorResume(ex -> Mono.just(errResult(input, ex)))
                .doFinally(s -> MDC.clear());
    }

    private WebOutput errResult(WebInput input, Throwable ex) {
        var error = GraphqlErrorBuilder
            .newError()
            .errorType(BAD_REQUEST)
            .message(ex.getMessage())
            .build();

        var result = ExecutionResultImpl.newExecutionResult().addError(error).build();
        return new WebOutput(input, result);
    }
...
}

Which is good enough for me.

Answered By – dpozinen

Answer Checked By – Cary Denson (Easybugfix Admin)

Leave a Reply

(*) Required, Your email will not be published