Replace RequestStrategy with GraphQlTransport hierarchy

See gh-317
This commit is contained in:
rstoyanchev
2022-03-04 09:04:26 +00:00
parent 9318eade52
commit 1ae7eb742f
11 changed files with 288 additions and 493 deletions

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2002-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.graphql.test.tester;
import java.util.List;
import graphql.ExecutionResult;
import graphql.GraphQLError;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.RequestOutput;
import org.springframework.graphql.client.GraphQlTransport;
import org.springframework.test.util.AssertionErrors;
import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.CollectionUtils;
import org.springframework.util.IdGenerator;
/**
* Abstract base class for a {@link GraphQlTransport} that makes a direct call
* to a server-side GraphQL handler or service.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
abstract class AbstractDirectTransport implements GraphQlTransport {
protected static final IdGenerator idGenerator = new AlternativeJdkIdGenerator();
@Override
public Mono<ExecutionResult> execute(GraphQlRequest request) {
return executeInternal(request).cast(ExecutionResult.class);
}
@SuppressWarnings({"ConstantConditions", "unchecked"})
@Override
public Flux<ExecutionResult> executeSubscription(GraphQlRequest request) {
return executeInternal(request).flatMapMany(result -> {
try {
Object data = result.getData();
AssertionErrors.assertTrue("Not a Publisher: " + data, data instanceof Publisher);
List<GraphQLError> errors = result.getErrors();
AssertionErrors.assertTrue("Subscription errors: " + errors, CollectionUtils.isEmpty(errors));
return Flux.from((Publisher<ExecutionResult>) data);
}
catch (AssertionError ex) {
throw new AssertionError(ex.getMessage() + "\nRequest: " + request, ex);
}
});
}
/**
* Subclasses must implement this to execute requests.
*/
protected abstract Mono<? extends RequestOutput> executeInternal(GraphQlRequest request);
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2002-2021 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.graphql.test.tester;
import java.time.Duration;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.jayway.jsonpath.Configuration;
import graphql.ExecutionResult;
import graphql.GraphQLError;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import org.springframework.graphql.RequestInput;
import org.springframework.lang.Nullable;
import org.springframework.test.util.AssertionErrors;
import org.springframework.util.CollectionUtils;
/**
* Base class for a {@link RequestStrategy} that performs GraphQL requests
* directly against a GraphQL Java server, i.e. without a client.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
class DirectRequestStrategySupport extends RequestStrategySupport {
protected DirectRequestStrategySupport(
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
super(errorFilter, jsonPathConfig, timeout);
}
protected GraphQlTester.ResponseSpec createResponseSpec(RequestInput input, ExecutionResult result) {
return createResponseSpec(result, assertDecorator(input));
}
protected GraphQlTester.SubscriptionSpec createSubscriptionSpec(RequestInput input, ExecutionResult result) {
Consumer<Runnable> assertDecorator = assertDecorator(input);
assertDecorator.accept(() -> AssertionErrors.assertTrue(
"Subscription did not return Publisher",
result.getData() instanceof Publisher));
assertDecorator.accept(() -> AssertionErrors.assertTrue(
"Response has " + result.getErrors().size() + " unexpected error(s).",
CollectionUtils.isEmpty(result.getErrors())));
return () -> {
Publisher<? extends ExecutionResult> publisher = result.getData();
return Flux.from(publisher).map((current) -> createResponseSpec(current, assertDecorator));
};
}
private Consumer<Runnable> assertDecorator(RequestInput input) {
return (assertion) -> {
try {
assertion.run();
}
catch (AssertionError ex) {
throw new AssertionError(ex.getMessage() + "\nRequest: " + input, ex);
}
};
}
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2002-2021 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.graphql.test.tester;
import java.time.Duration;
import java.util.function.Predicate;
import com.jayway.jsonpath.Configuration;
import graphql.ExecutionResult;
import graphql.GraphQLError;
import org.springframework.graphql.GraphQlService;
import org.springframework.graphql.RequestInput;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link RequestStrategy} that performs requests via {@link GraphQlService}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class GraphQlServiceRequestStrategy extends DirectRequestStrategySupport implements RequestStrategy {
private final GraphQlService graphQlService;
public GraphQlServiceRequestStrategy(GraphQlService service,
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
super(errorFilter, jsonPathConfig, timeout);
Assert.notNull(service, "GraphQlService is required.");
this.graphQlService = service;
}
@Override
public GraphQlTester.ResponseSpec execute(RequestInput input) {
return createResponseSpec(input, executeInternal(input));
}
@Override
public GraphQlTester.SubscriptionSpec executeSubscription(RequestInput input) {
return createSubscriptionSpec(input, executeInternal(input));
}
private ExecutionResult executeInternal(RequestInput input) {
ExecutionResult result = this.graphQlService.execute(input).block(getResponseTimeout());
Assert.notNull(result, "Expected ExecutionResult");
return result;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2002-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.graphql.test.tester;
import reactor.core.publisher.Mono;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlService;
import org.springframework.graphql.RequestInput;
import org.springframework.graphql.RequestOutput;
import org.springframework.util.Assert;
/**
* {@code GraphQlTransport} that calls directly a {@link GraphQlService}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class GraphQlServiceTransport extends AbstractDirectTransport {
private final GraphQlService graphQlService;
GraphQlServiceTransport(GraphQlService graphQlService) {
Assert.notNull(graphQlService, "GraphQlService is required");
this.graphQlService = graphQlService;
}
public GraphQlService getGraphQlService() {
return this.graphQlService;
}
@Override
protected Mono<RequestOutput> executeInternal(GraphQlRequest request) {
RequestInput requestInput = new RequestInput(
request.getDocument(), request.getOperationName(), request.getVariables(),
idGenerator.generateId().toString(), null);
return this.graphQlService.execute(requestInput);
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2002-2021 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.graphql.test.tester;
import org.springframework.graphql.RequestInput;
/**
* Abstracts how a GraphQL request is performed, given {@link RequestInput}, and
* resulting in the creation of a response spec.
*
* <p>For internal use use from {@link DefaultGraphQlTester}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
interface RequestStrategy {
/**
* Perform a request with the given {@link RequestInput} container.
* @param input the request input
* @return the response spec
*/
GraphQlTester.ResponseSpec execute(RequestInput input);
/**
* Perform a subscription with the given {@link RequestInput} container.
* @param input the request input
* @return the subscription spec
*/
GraphQlTester.SubscriptionSpec executeSubscription(RequestInput input);
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2002-2021 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.graphql.test.tester;
import java.time.Duration;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import graphql.ExecutionResult;
import graphql.GraphQLError;
import org.springframework.lang.Nullable;
/**
* Base class support for {@link RequestStrategy} and
* {@link WebRequestStrategy} implementations.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
class RequestStrategySupport {
@Nullable
private final Predicate<GraphQLError> errorFilter;
private final Configuration jsonPathConfig;
private final Duration responseTimeout;
protected RequestStrategySupport(
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
this.errorFilter = errorFilter;
this.jsonPathConfig = jsonPathConfig;
this.responseTimeout = timeout;
}
protected Configuration getJsonPathConfig() {
return this.jsonPathConfig;
}
protected Duration getResponseTimeout() {
return this.responseTimeout;
}
protected GraphQlTester.ResponseSpec createResponseSpec(
ExecutionResult result, Consumer<Runnable> assertDecorator) {
DocumentContext context = JsonPath.parse(result.toSpecification(), this.jsonPathConfig);
return createResponseSpec(context, assertDecorator);
}
protected GraphQlTester.ResponseSpec createResponseSpec(
DocumentContext context, Consumer<Runnable> assertDecorator) {
return DefaultGraphQlTester.createResponseSpec(context, this.errorFilter, assertDecorator);
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2002-2021 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.graphql.test.tester;
import java.time.Duration;
import java.util.function.Predicate;
import com.jayway.jsonpath.Configuration;
import graphql.GraphQLError;
import org.springframework.graphql.web.WebGraphQlHandler;
import org.springframework.graphql.web.WebInput;
import org.springframework.graphql.web.WebOutput;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link WebRequestStrategy} that performs requests directly against a
* {@link WebGraphQlHandler}, i.e. without a client.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
class WebGraphQlHandlerRequestStrategy extends DirectRequestStrategySupport implements WebRequestStrategy {
private final WebGraphQlHandler graphQlHandler;
WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler,
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
super(errorFilter, jsonPathConfig, timeout);
this.graphQlHandler = handler;
}
@Override
public WebGraphQlTester.WebResponseSpec execute(WebInput input) {
WebOutput webOutput = executeInternal(input);
GraphQlTester.ResponseSpec responseSpec = createResponseSpec(input, webOutput);
return DefaultWebGraphQlTester.createResponseSpec(responseSpec, webOutput.getResponseHeaders());
}
@Override
public WebGraphQlTester.WebSubscriptionSpec executeSubscription(WebInput input) {
WebOutput webOutput = executeInternal(input);
GraphQlTester.SubscriptionSpec subscriptionSpec = createSubscriptionSpec(input, webOutput);
return DefaultWebGraphQlTester.createSubscriptionSpec(subscriptionSpec, webOutput.getResponseHeaders());
}
private WebOutput executeInternal(WebInput webInput) {
WebOutput webOutput = this.graphQlHandler.handleRequest(webInput).block(getResponseTimeout());
Assert.notNull(webOutput, "Expected WebOutput");
return webOutput;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2002-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.graphql.test.tester;
import java.net.URI;
import reactor.core.publisher.Mono;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.web.WebGraphQlHandler;
import org.springframework.graphql.web.WebInput;
import org.springframework.graphql.web.WebOutput;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
/**
* {@code GraphQlTransport} that calls directly a {@link WebGraphQlHandler}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class WebGraphQlHandlerTransport extends AbstractDirectTransport {
private final URI url;
private final HttpHeaders headers = new HttpHeaders();
private final WebGraphQlHandler graphQlHandler;
WebGraphQlHandlerTransport(@Nullable URI url, HttpHeaders headers, WebGraphQlHandler graphQlHandler) {
this.url = (url != null ? url : URI.create(""));
this.headers.addAll(headers);
this.graphQlHandler = graphQlHandler;
}
public URI getUrl() {
return this.url;
}
public HttpHeaders getHeaders() {
return this.headers;
}
public WebGraphQlHandler getGraphQlHandler() {
return this.graphQlHandler;
}
@Override
protected Mono<WebOutput> executeInternal(GraphQlRequest request) {
return this.graphQlHandler.handleRequest(
new WebInput(this.url, this.headers, request.toMap(), idGenerator.generateId().toString(), null));
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2002-2021 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.graphql.test.tester;
import org.springframework.graphql.web.WebInput;
/**
* Abstracts how a GraphQL request is performed in the a Web context, given
* {@link WebInput}, and resulting in the creation of a response spec.
*
* <p>For internal use use from {@link DefaultWebGraphQlTester}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
interface WebRequestStrategy {
/**
* Perform a request with the given {@link WebInput}.
* @param input the request input
* @return the response spec
*/
WebGraphQlTester.WebResponseSpec execute(WebInput input);
/**
* Perform a subscription with the given {@link WebInput}.
* @param input the request input
* @return the subscription spec
*/
WebGraphQlTester.WebSubscriptionSpec executeSubscription(WebInput input);
}

View File

@@ -1,108 +0,0 @@
/*
* Copyright 2002-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.graphql.test.tester;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collections;
import java.util.Locale;
import java.util.function.Predicate;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import graphql.GraphQLError;
import reactor.core.publisher.Flux;
import org.springframework.graphql.web.WebInput;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.test.web.reactive.server.EntityExchangeResult;
import org.springframework.test.web.reactive.server.FluxExchangeResult;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.Assert;
/**
* {@link WebRequestStrategy} that uses {@link WebTestClient} to perform
* requests. Depending on how the client is configured, this may be used with
* Spring MVC and WebFlux controllers, without a server, or against a live server.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class WebTestClientRequestStrategy extends RequestStrategySupport implements WebRequestStrategy {
private final WebTestClient client;
WebTestClientRequestStrategy(WebTestClient client,
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration responseTimeout) {
super(errorFilter, jsonPathConfig, responseTimeout);
this.client = client;
}
@Override
public WebGraphQlTester.WebResponseSpec execute(WebInput webInput) {
EntityExchangeResult<byte[]> result = this.client.post()
.contentType(MediaType.APPLICATION_JSON)
.headers(headers -> headers.putAll(webInput.getHeaders()))
.bodyValue(webInput.toMap())
.exchange()
.expectStatus()
.isOk()
.expectHeader()
.contentTypeCompatibleWith(MediaType.APPLICATION_JSON)
.expectBody()
.returnResult();
byte[] bytes = result.getResponseBodyContent();
Assert.notNull(bytes, "Expected GraphQL response content");
String content = new String(bytes, StandardCharsets.UTF_8);
DocumentContext documentContext = JsonPath.parse(content, getJsonPathConfig());
GraphQlTester.ResponseSpec responseSpec = createResponseSpec(documentContext, result::assertWithDiagnostics);
return DefaultWebGraphQlTester.createResponseSpec(responseSpec, result.getResponseHeaders());
}
@Override
public WebGraphQlTester.WebSubscriptionSpec executeSubscription(WebInput webInput) {
FluxExchangeResult<TestExecutionResult> exchangeResult = this.client.post()
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.TEXT_EVENT_STREAM)
.headers(headers -> {
Locale locale = webInput.getLocale();
if (locale != null) {
headers.setAcceptLanguageAsLocales(Collections.singletonList(locale));
}
headers.putAll(webInput.getHeaders());
})
.bodyValue(webInput.toMap())
.exchange()
.expectStatus()
.isOk()
.expectHeader()
.contentType(MediaType.TEXT_EVENT_STREAM)
.returnResult(TestExecutionResult.class);
Flux<GraphQlTester.ResponseSpec> flux = exchangeResult.getResponseBody()
.map((result) -> createResponseSpec(result, exchangeResult::assertWithDiagnostics));
return DefaultWebGraphQlTester.createSubscriptionSpec(() -> flux, exchangeResult.getResponseHeaders());
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2002-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.graphql.test.tester;
import java.util.Collections;
import java.util.Map;
import graphql.ExecutionResult;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.client.GraphQlTransport;
import org.springframework.graphql.support.MapExecutionResult;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.Assert;
/**
* {@code GraphQlTransport} for GraphQL over HTTP via {@link WebTestClient}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class WebTestClientTransport implements GraphQlTransport {
private static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE =
new ParameterizedTypeReference<Map<String, Object>>() {};
private final WebTestClient webTestClient;
WebTestClientTransport(WebTestClient webTestClient) {
Assert.notNull(webTestClient, "WebTestClient is required");
this.webTestClient = webTestClient;
}
@Override
public Mono<ExecutionResult> execute(GraphQlRequest request) {
Map<String, Object> resultMap = this.webTestClient.post()
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.bodyValue(request.toMap())
.exchange()
.expectStatus().isOk()
.expectHeader().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)
.expectBody(MAP_TYPE)
.returnResult()
.getResponseBody();
resultMap = (resultMap != null ? resultMap : Collections.emptyMap());
ExecutionResult result = MapExecutionResult.from(resultMap);
return Mono.just(result);
}
@Override
public Flux<ExecutionResult> executeSubscription(GraphQlRequest request) {
throw new UnsupportedOperationException("Subscriptions not supported over HTTP");
}
}