For the latest stable version, please use Spring Integration 6.4.0!

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

  • Gradle

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-graphql</artifactId>
    <version>6.3.6</version>
</dependency>
compile "org.springframework.integration:spring-integration-graphql:6.3.6"

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 an 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 the 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
GraphQlMessageHandlerSpec graphQlMessageHandlerSpec(ExecutionGraphQlService graphQlService) {
    return GraphQl.gateway(graphQlService)
            .operation("""
                    query HeroNameAndFriends($episode: Episode) {
                      hero(episode: $episode) {
                        name
                        friends {
                          name
                        }
                      }
                    }""")
            .variablesExpression("{episode:'JEDI'}");
}

@Bean
IntegrationFlow graphqlQueryMessageHandlerFlow(GraphQlMessageHandler handler) {
    return IntegrationFlow.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 ExecutionGraphQlResponse.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(ExecutionGraphQlResponse graphQlResponse) {
	return graphQlResponse.getData();
}

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 produced as a reply to the upstream request or sent downstream for further processing in the integration flow.