GraphQL Support

Spring Integration provides channel adapters for interaction with GraphQL protocol. The implementation is based on the Spring for GraphQL.

You need to include this dependency into your project:

Maven
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-graphql</artifactId>
    <version>6.0.0-M3</version>
</dependency>
Gradle
compile "org.springframework.integration:spring-integration-graphql:6.0.0-M3"

GraphQL Outbound Gateway

The GraphQlMessageHandler is an AbstractReplyProducingMessageHandler extension representing an outbound gateway contract to perform GraphQL query, mutation or subscription operation and produce their result. It requires a org.springframework.graphql.ExecutionGraphQlService for execution of operation, which can be configured statically or via SpEL expression against a request message. The operationName is optional and also can be configured statically or via SpEL expression. The variablesExpression is also optional and used for parametrized operations. The locale is optional and used for operation execution context in the GraphQL Java library. The executionId can be configured via SpEL expression and defaults to id header of the request message.

If the payload of request message is an instance of ExecutionGraphQlRequest, then there’s no any setup actions are performed in the GraphQlMessageHandler and such an input is used as is for the ExecutionGraphQlService.execute(). Otherwise, the operation, operationName, variables and executionId are determined against request message using SpEL expressions mentioned above.

The GraphQlMessageHandler is a reactive streams component and produces a Mono<ExecutionGraphQlResponse> reply as a result of the ExecutionGraphQlService.execute(ExecutionGraphQlRequest). Such a Mono is subscribed by the framework in the ReactiveStreamsSubscribableChannel output channel or in the AbstractMessageProducingHandler asynchronously when the output channel is not reactive. See documentation for the ExecutionGraphQlResponse how to process the GraphQL operation result.

@Bean
GraphQlMessageHandler handler(ExecutionGraphQlService graphQlService) {
    GraphQlMessageHandler graphQlMessageHandler = new GraphQlMessageHandler(graphQlService);
    graphQlMessageHandler.setOperation("""
            query HeroNameAndFriends($episode: Episode) {
              hero(episode: $episode) {
                name
                friends {
                  name
                }
              }
            }""");
    graphQlMessageHandler.setVariablesExpression(new SpelExpressionParser().parseExpression("{episode:'JEDI'}"));
    return graphQlMessageHandler;
}

@Bean
IntegrationFlow graphqlQueryMessageHandlerFlow(GraphQlMessageHandler handler) {
    return IntegrationFlows.from(MessageChannels.flux("inputChannel"))
            .handle(handler)
            .channel(c -> c.flux("resultChannel"))
            .get();
}

@Bean
ExecutionGraphQlService graphQlService(GraphQlSource graphQlSource) {
    return new DefaultExecutionGraphQlService(graphQlSource);
}

@Bean
GraphQlSource graphQlSource(AnnotatedControllerConfigurer annotatedDataFetcherConfigurer) {
    return GraphQlSource.builder()
            .schemaResources(new ClassPathResource("graphql/test-schema.graphqls"))
            .configureRuntimeWiring(annotatedDataFetcherConfigurer)
            .build();
}

@Bean
AnnotatedControllerConfigurer annotatedDataFetcherConfigurer() {
    return new AnnotatedControllerConfigurer();
}

The special treatment should be applied for the result of a subscription operation. In this case the RequestOutput.getData() returns a SubscriptionPublisher which has to subscribed and processed manually. Or it can be flat-mapped via plain service activator to the reply for the FluxMessageChannel:

@ServiceActivator(inputChannel = "graphQlResultChannel", outputChannel="graphQlSubscriptionChannel")
public SubscriptionPublisher obtainSubscriptionResult(RequestOutput output) {
	return output.getData(0);
}

Such an outbound gateway can be used not only for GraphQL request via HTTP, but from any upstream endpoint which produces or carries a GraphQL operation or its arguments in the message. The result of the GraphQlMessageHandler handling can be produces as a reply to the upstream request or sent downstream for further processing in the integration flow.