GH-3501: Add GraphQL support
Fixes https://github.com/spring-projects/spring-integration/issues/3501 * make current with latest changes in 'spring-graphql' * fix checkstyle issues * implement reactive endpoint for GraphQL Query * refactor to handle GraphQL Query and Mutation requests * refactor to handle GraphQL Subscription requests * implement expressions to handle for various RequestInput parameters * convert classes to records in tests, remove unneeded datatype modifiers on channels * replace executionId with idExpression SpEL evaluator * adjust name and default expression for executionId * rename for consistency, remove unneeded null check * Clean up code style * Remove redundant variables * Add `What's New` entry * Add `package-info.java`
This commit is contained in:
@@ -99,6 +99,7 @@ ext {
|
||||
smackVersion = '4.3.5'
|
||||
springAmqpVersion = project.hasProperty('springAmqpVersion') ? project.springAmqpVersion : '3.0.0-M1'
|
||||
springDataVersion = project.hasProperty('springDataVersion') ? project.springDataVersion : '2022.0.0-M1'
|
||||
springGraphqlVersion = '1.0.0-M5'
|
||||
springKafkaVersion = '3.0.0-M1'
|
||||
springRetryVersion = '1.3.1'
|
||||
springSecurityVersion = project.hasProperty('springSecurityVersion') ? project.springSecurityVersion : '6.0.0-M1'
|
||||
@@ -613,6 +614,14 @@ project('spring-integration-gemfire') {
|
||||
}
|
||||
}
|
||||
|
||||
project('spring-integration-graphql') {
|
||||
description = 'Spring Integration GraphQL Support'
|
||||
dependencies {
|
||||
api project(':spring-integration-core')
|
||||
api "org.springframework.graphql:spring-graphql:$springGraphqlVersion"
|
||||
}
|
||||
}
|
||||
|
||||
project('spring-integration-groovy') {
|
||||
description = 'Spring Integration Groovy Support'
|
||||
dependencies {
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.graphql.outbound;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.expression.FunctionExpression;
|
||||
import org.springframework.integration.expression.SupplierExpression;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AbstractReplyProducingMessageHandler} capable of fielding
|
||||
* GraphQL Query, Mutation and Subscription requests.
|
||||
*
|
||||
* @author Daniel Frey
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public class GraphQlMessageHandler extends AbstractReplyProducingMessageHandler {
|
||||
|
||||
private final GraphQlService graphQlService;
|
||||
|
||||
private StandardEvaluationContext evaluationContext;
|
||||
|
||||
private Expression operationExpression;
|
||||
|
||||
private Expression operationNameExpression = new SupplierExpression<>(() -> null);
|
||||
|
||||
private Expression variablesExpression = new SupplierExpression<>(() -> null);
|
||||
|
||||
@Nullable
|
||||
private Locale locale;
|
||||
|
||||
private Expression executionIdExpression =
|
||||
new FunctionExpression<Message<?>>(message -> message.getHeaders().getId());
|
||||
|
||||
public GraphQlMessageHandler(final GraphQlService graphQlService) {
|
||||
Assert.notNull(graphQlService, "'graphQlService' must not be null");
|
||||
this.graphQlService = graphQlService;
|
||||
setAsync(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a GraphQL Operation.
|
||||
* @param operation the GraphQL operation to use.
|
||||
*/
|
||||
public void setOperation(String operation) {
|
||||
Assert.hasText(operation, "'operation' must not be empty");
|
||||
setOperationExpression(new LiteralExpression(operation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a SpEL expression to evaluate a GraphQL Operation
|
||||
* @param operationExpression the expression to evaluate a GraphQL Operation.
|
||||
*/
|
||||
public void setOperationExpression(Expression operationExpression) {
|
||||
Assert.notNull(operationExpression, "'queryExpression' must not be null");
|
||||
this.operationExpression = operationExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a GraphQL Operation Name to execute.
|
||||
* @param operationName the GraphQL Operation Name to use.
|
||||
*/
|
||||
public void setOperationName(String operationName) {
|
||||
setOperationNameExpression(new LiteralExpression(operationName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a SpEL expression to evaluate a GraphQL Operation Name to execute.
|
||||
* @param operationNameExpression the expression to use.
|
||||
*/
|
||||
public void setOperationNameExpression(Expression operationNameExpression) {
|
||||
Assert.notNull(operationNameExpression, "'operationNameExpression' must not be null");
|
||||
this.operationNameExpression = operationNameExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a SpEL expression to evaluate Variables for GraphQL Operation to execute.
|
||||
* @param variablesExpression the expression to use.
|
||||
*/
|
||||
public void setVariablesExpression(Expression variablesExpression) {
|
||||
Assert.notNull(variablesExpression, "'variablesExpression' must not be null");
|
||||
this.variablesExpression = variablesExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Locale for GraphQL Operation to execute.
|
||||
* @param locale the locale to use.
|
||||
*/
|
||||
public void setLocale(@Nullable Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a SpEL expression to evaluate Execution Id for GraphQL Operation Request to execute.
|
||||
* @param executionIdExpression the executionIdExpression to use.
|
||||
*/
|
||||
public void setExecutionIdExpression(Expression executionIdExpression) {
|
||||
Assert.notNull(executionIdExpression, "'executionIdExpression' must not be null");
|
||||
this.executionIdExpression = executionIdExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void doInit() {
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
RequestInput requestInput;
|
||||
|
||||
if (requestMessage.getPayload() instanceof RequestInput) {
|
||||
requestInput = (RequestInput) requestMessage.getPayload();
|
||||
}
|
||||
else {
|
||||
Assert.notNull(this.operationExpression, "'operationExpression' must not be null");
|
||||
String query = evaluateOperationExpression(requestMessage);
|
||||
String operationName = evaluateOperationNameExpression(requestMessage);
|
||||
Map<String, Object> variables = evaluateVariablesExpression(requestMessage);
|
||||
String id = evaluateExecutionIdExpression(requestMessage);
|
||||
requestInput = new RequestInput(query, operationName, variables, this.locale, id);
|
||||
}
|
||||
|
||||
return this.graphQlService.execute(requestInput);
|
||||
|
||||
}
|
||||
|
||||
private String evaluateOperationExpression(Message<?> message) {
|
||||
String operation = this.operationExpression.getValue(this.evaluationContext, message, String.class);
|
||||
Assert.notNull(operation, "'operationExpression' must not evaluate to null");
|
||||
return operation;
|
||||
}
|
||||
|
||||
private String evaluateOperationNameExpression(Message<?> message) {
|
||||
return this.operationNameExpression.getValue(this.evaluationContext, message, String.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> evaluateVariablesExpression(Message<?> message) {
|
||||
return this.variablesExpression.getValue(this.evaluationContext, message, Map.class);
|
||||
}
|
||||
|
||||
private String evaluateExecutionIdExpression(Message<?> message) {
|
||||
return this.executionIdExpression.getValue(this.evaluationContext, message, String.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes for GraphQL outbound channel adapters.
|
||||
*/
|
||||
package org.springframework.integration.graphql.outbound;
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.graphql.outbound;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
import org.springframework.graphql.RequestOutput;
|
||||
import org.springframework.graphql.data.method.annotation.Argument;
|
||||
import org.springframework.graphql.data.method.annotation.MutationMapping;
|
||||
import org.springframework.graphql.data.method.annotation.QueryMapping;
|
||||
import org.springframework.graphql.data.method.annotation.SubscriptionMapping;
|
||||
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
|
||||
import org.springframework.graphql.execution.ExecutionGraphQlService;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.integration.channel.FluxMessageChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.dsl.IntegrationFlow;
|
||||
import org.springframework.integration.dsl.IntegrationFlows;
|
||||
import org.springframework.integration.dsl.MessageChannels;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import graphql.execution.reactive.SubscriptionPublisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Daniel Frey
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
public class GraphQlMessageHandlerTests {
|
||||
|
||||
@Autowired
|
||||
private FluxMessageChannel inputChannel;
|
||||
|
||||
@Autowired
|
||||
private FluxMessageChannel resultChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel errorChannel;
|
||||
|
||||
@Autowired
|
||||
private GraphQlMessageHandler graphQlMessageHandler;
|
||||
|
||||
@Autowired
|
||||
private UpdateRepository updateRepository;
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void testHandleMessageForQueryWithRequestInputProvided() {
|
||||
StepVerifier verifier =
|
||||
StepVerifier.create(
|
||||
Flux.from(this.resultChannel)
|
||||
.map(Message::getPayload)
|
||||
.cast(RequestOutput.class)
|
||||
)
|
||||
.consumeNextWith(result -> {
|
||||
assertThat(result).isInstanceOf(RequestOutput.class);
|
||||
Map<String, Object> data = result.getData();
|
||||
Map<String, Object> testQuery = (Map<String, Object>) data.get("testQuery");
|
||||
assertThat(testQuery.get("id")).isEqualTo("test-data");
|
||||
})
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
|
||||
RequestInput payload = new RequestInput("{ testQuery { id } }", null, null, null, UUID.randomUUID().toString());
|
||||
this.inputChannel.send(MessageBuilder.withPayload(payload).build());
|
||||
|
||||
verifier.verify(Duration.ofSeconds(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void testHandleMessageForQueryWithQueryProvided() {
|
||||
String fakeQuery = "{ testQuery { id } }";
|
||||
this.graphQlMessageHandler.setOperation(fakeQuery);
|
||||
|
||||
Locale locale = Locale.getDefault();
|
||||
this.graphQlMessageHandler.setLocale(locale);
|
||||
|
||||
Mono<RequestOutput> resultMono =
|
||||
(Mono<RequestOutput>) this.graphQlMessageHandler.handleRequestMessage(new GenericMessage<>(fakeQuery));
|
||||
StepVerifier.create(resultMono)
|
||||
.consumeNextWith(result -> {
|
||||
assertThat(result).isInstanceOf(RequestOutput.class);
|
||||
Map<String, Object> data = result.getData();
|
||||
Map<String, Object> testQuery = (Map<String, Object>) data.get("testQuery");
|
||||
assertThat(testQuery.get("id")).isEqualTo("test-data");
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void testHandleMessageForMutationWithRequestInputProvided() {
|
||||
String fakeId = UUID.randomUUID().toString();
|
||||
Update expected = new Update(fakeId);
|
||||
|
||||
StepVerifier verifier = StepVerifier.create(
|
||||
Flux.from(this.resultChannel)
|
||||
.map(Message::getPayload)
|
||||
.cast(RequestOutput.class)
|
||||
)
|
||||
.consumeNextWith(result -> {
|
||||
assertThat(result).isInstanceOf(RequestOutput.class);
|
||||
Map<String, Object> data = result.getData();
|
||||
Map<String, Object> update = (Map<String, Object>) data.get("update");
|
||||
assertThat(update.get("id")).isEqualTo(fakeId);
|
||||
|
||||
assertThat(this.updateRepository.current().block()).isEqualTo(expected);
|
||||
}
|
||||
)
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
|
||||
RequestInput payload =
|
||||
new RequestInput("mutation { update(id: \"" + fakeId + "\") { id } }", null, null, null,
|
||||
UUID.randomUUID().toString());
|
||||
this.inputChannel.send(MessageBuilder.withPayload(payload).build());
|
||||
|
||||
verifier.verify(Duration.ofSeconds(10));
|
||||
|
||||
StepVerifier.create(this.updateRepository.current())
|
||||
.expectNext(expected)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void testHandleMessageForSubscriptionWithRequestInputProvided() {
|
||||
StepVerifier verifier = StepVerifier.create(
|
||||
Flux.from(this.resultChannel)
|
||||
.map(Message::getPayload)
|
||||
.cast(RequestOutput.class)
|
||||
.mapNotNull(RequestOutput::getData)
|
||||
.cast(SubscriptionPublisher.class)
|
||||
.map(Flux::from)
|
||||
.flatMap(data -> data)
|
||||
)
|
||||
.consumeNextWith(requestOutput -> {
|
||||
Map<String, Object> results = requestOutput.getData();
|
||||
assertThat(results).containsKey("results");
|
||||
|
||||
Map<String, Object> operationResult = (Map<String, Object>) results.get("results");
|
||||
assertThat(operationResult)
|
||||
.containsKey("id")
|
||||
.containsValue("test-data-01");
|
||||
|
||||
})
|
||||
.expectNextCount(9)
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
|
||||
RequestInput payload =
|
||||
new RequestInput("subscription { results { id } }", null, null, null, UUID.randomUUID().toString());
|
||||
this.inputChannel.send(MessageBuilder.withPayload(payload).build());
|
||||
|
||||
verifier.verify(Duration.ofSeconds(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleMessageWithInvalidPayload() {
|
||||
this.inputChannel.send(MessageBuilder.withPayload(new Object()).build());
|
||||
|
||||
Message<?> errorMessage = errorChannel.receive(10_000);
|
||||
assertThat(errorMessage).isNotNull()
|
||||
.isInstanceOf(ErrorMessage.class)
|
||||
.extracting(Message::getPayload)
|
||||
.isInstanceOf(MessageHandlingException.class)
|
||||
.satisfies((ex) -> assertThat((Exception) ex)
|
||||
.hasMessageContaining(
|
||||
"'operationExpression' must not be null"));
|
||||
}
|
||||
|
||||
@Controller
|
||||
static class GraphQlController {
|
||||
|
||||
final UpdateRepository updateRepository;
|
||||
|
||||
GraphQlController(UpdateRepository updateRepository) {
|
||||
this.updateRepository = updateRepository;
|
||||
}
|
||||
|
||||
@QueryMapping
|
||||
public Mono<QueryResult> testQuery() {
|
||||
return Mono.just(new QueryResult("test-data"));
|
||||
}
|
||||
|
||||
@QueryMapping
|
||||
public Mono<QueryResult> testQueryById(@Argument String id) {
|
||||
return Mono.just(new QueryResult("test-data"));
|
||||
}
|
||||
|
||||
@MutationMapping
|
||||
public Mono<Update> update(@Argument String id) {
|
||||
return this.updateRepository.save(new Update(id));
|
||||
}
|
||||
|
||||
@SubscriptionMapping
|
||||
public Flux<QueryResult> results() {
|
||||
return Flux.just(
|
||||
new QueryResult("test-data-01"),
|
||||
new QueryResult("test-data-02"),
|
||||
new QueryResult("test-data-03"),
|
||||
new QueryResult("test-data-04"),
|
||||
new QueryResult("test-data-05"),
|
||||
new QueryResult("test-data-06"),
|
||||
new QueryResult("test-data-07"),
|
||||
new QueryResult("test-data-08"),
|
||||
new QueryResult("test-data-09"),
|
||||
new QueryResult("test-data-10")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Repository
|
||||
static class UpdateRepository {
|
||||
|
||||
private Update current;
|
||||
|
||||
Mono<Update> save(Update update) {
|
||||
this.current = update;
|
||||
return Mono.justOrEmpty(this.current);
|
||||
}
|
||||
|
||||
Mono<Update> current() {
|
||||
return Mono.just(this.current);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
static class TestConfig {
|
||||
|
||||
@Bean
|
||||
GraphQlMessageHandler handler(GraphQlService graphQlService) {
|
||||
|
||||
return new GraphQlMessageHandler(graphQlService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
IntegrationFlow graphqlQueryMessageHandlerFlow(GraphQlMessageHandler handler) {
|
||||
return IntegrationFlows.from(MessageChannels.flux("inputChannel"))
|
||||
.handle(handler)
|
||||
.channel(c -> c.flux("resultChannel"))
|
||||
.get();
|
||||
}
|
||||
|
||||
@Bean
|
||||
PollableChannel errorChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
UpdateRepository updateRepository() {
|
||||
return new UpdateRepository();
|
||||
}
|
||||
|
||||
@Bean
|
||||
GraphQlController graphqlQueryController(UpdateRepository updateRepository) {
|
||||
return new GraphQlController(updateRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
GraphQlService graphQlService(GraphQlSource graphQlSource) {
|
||||
return new ExecutionGraphQlService(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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record QueryResult(String id) {
|
||||
|
||||
}
|
||||
|
||||
record Update(String id) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
type Query {
|
||||
testQuery: QueryResult
|
||||
testQueryById(id: String): QueryResult
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
update(id: String!): Update!
|
||||
}
|
||||
|
||||
type Subscription {
|
||||
results: QueryResult
|
||||
}
|
||||
|
||||
type QueryResult {
|
||||
id: String
|
||||
}
|
||||
|
||||
type Update {
|
||||
id: String
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
<Console name="STDOUT" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d %p [%t] [%c] - %m%n" />
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="org.springframework" level="warn"/>
|
||||
<Logger name="org.springframework.graphql" level="warn"/>
|
||||
<Logger name="org.springframework.integration.graphql" level="warn"/>
|
||||
<Root level="warn">
|
||||
<AppenderRef ref="STDOUT" />
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
23
src/reference/asciidoc/graphql.adoc
Normal file
23
src/reference/asciidoc/graphql.adoc
Normal file
@@ -0,0 +1,23 @@
|
||||
[[graphql]]
|
||||
== GraphQL Support
|
||||
|
||||
Spring Integration provides support for GraphQL.
|
||||
|
||||
You need to include this dependency into your project:
|
||||
|
||||
====
|
||||
[source, xml, subs="normal", role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-graphql</artifactId>
|
||||
<version>{project-version}</version>
|
||||
</dependency>
|
||||
----
|
||||
[source, groovy, subs="normal", role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
compile "org.springframework.integration:spring-integration-graphql:{project-version}"
|
||||
----
|
||||
====
|
||||
@@ -41,6 +41,8 @@ include::./ftp.adoc[]
|
||||
|
||||
include::./gemfire.adoc[]
|
||||
|
||||
include::./graphql.adoc[]
|
||||
|
||||
include::./http.adoc[]
|
||||
|
||||
include::./jdbc.adoc[]
|
||||
|
||||
@@ -30,6 +30,7 @@ This documentation is also available as single searchable link:index-single.html
|
||||
<<./file.adoc#files,File Support>> ::
|
||||
<<./ftp.adoc#ftp,FTP/FTPS Adapters>> ::
|
||||
<<./gemfire.adoc#gemfire,Pivotal GemFire and Apache Geode Support>> ::
|
||||
<<./graphql.adoc#graphql,GraphQL Support>> ::
|
||||
<<./http.adoc#http,HTTP Support>> ::
|
||||
<<./jdbc.adoc#jdbc,JDBC Support>> ::
|
||||
<<./jpa.adoc#jpa,JPA Support>> ::
|
||||
|
||||
@@ -17,6 +17,12 @@ In general the project has been moved to Java 17 baseline and migrated from Java
|
||||
[[x6.0-new-components]]
|
||||
=== New Components
|
||||
|
||||
[[x6.0-graphql]]
|
||||
=== GraphQL Support
|
||||
|
||||
The GraphQL support has been added.
|
||||
See <<./graphql.adoc#graphql,GraphQL Support>> for more information.
|
||||
|
||||
[[x6.0-general]]
|
||||
=== General Changes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user