leangen / graphql-spqr

Build a GraphQL service in seconds
Apache License 2.0
1.09k stars 181 forks source link

Enable ResolverInterceptors to optionally run after output conversion #463

Closed kaqqao closed 1 year ago

kaqqao commented 1 year ago

ResolverInterceptors currently run directly around the underlying method invocation. This is intuitive, as the the result of proceed(...) will be the whatever the method returned, unmodified. However, it is sometimes useful to obtain the converted result (the result after OutputConverters have been applied to it). A good use-case for this is wrapping the already processed result (or, more often, the exception) into a DataFetcherResult, or running the underlying method asynchronously, turning the result into a CompletableFuture.

This can all be achieved using the existing method interception facility, it is only necessary to clearly demarcate when each interceptor is supposed to run in relation to output conversion.

Changes:

Example:

public class TestService {
    @GraphQLQuery
    // Returns a result that normally gets converted, e.g. a Stream is converted to a List on the way out
    public Stream<String> stream() {
        return Stream.of("aaa", "bbb");
    }
}

public class TestInterceptor implements ResolverInterceptor {

    @Override
    public Object aroundInvoke(InvocationContext context, Continuation continuation) throws Exception {
        Object result = continuation.proceed(context);
        System.out.println(result instanceof Stream ? "Got Stream" : "Got List");
        return result;
    }
}

generator
    .withOperationsFromSingleton(new TestService())
    .withResolverInterceptors(new TestInterceptor()) // This TestInterceptor will print "Got Stream"
    .withOuterResolverInterceptors(new TestInterceptor()) // This TestInterceptor will print "Got List"

See Javadoc on ResolverInterceptorFactory and the related tests for more detailed examples (applying interceptors only to specific methods etc).