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:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-graphql</artifactId>
<version>6.0.13</version>
</dependency>
compile "org.springframework.integration:spring-integration-graphql:6.0.13"
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
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 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 produced as a reply to the upstream request or sent downstream for further processing in the integration flow.