Deserialize HTTP request body to POJO

Closes gh-905
This commit is contained in:
rstoyanchev
2024-02-08 20:54:55 +00:00
parent 1736d2abf0
commit fb1f0ee0e7
15 changed files with 220 additions and 137 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -79,7 +79,7 @@ final class WebGraphQlHandlerGraphQlTransport extends AbstractDirectGraphQlTrans
protected Mono<ExecutionGraphQlResponse> executeInternal(ExecutionGraphQlRequest executionRequest) {
WebGraphQlRequest request = new WebGraphQlRequest(
this.url, this.headers, null, Collections.emptyMap(), executionRequest.toMap(),
this.url, this.headers, null, Collections.emptyMap(), executionRequest,
idGenerator.generateId().toString(), null);
return this.graphQlHandler.handleRequest(request).cast(ExecutionGraphQlResponse.class);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 the original author or authors.
* Copyright 2020-2024 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.
@@ -22,6 +22,7 @@ import java.util.Locale;
import java.util.Map;
import org.springframework.graphql.ExecutionGraphQlRequest;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.support.DefaultExecutionGraphQlRequest;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
@@ -60,15 +61,6 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
private final Map<String, Object> attributes;
/**
* Create an instance.
* @deprecated as of 1.1.3 in favor of the constructor with cookies
*/
@Deprecated
public WebGraphQlRequest(URI uri, HttpHeaders headers, Map<String, Object> body, String id, @Nullable Locale locale) {
this(uri, headers, null, Collections.emptyMap(), body, id, locale);
}
/**
* Create an instance.
* @param uri the URL for the HTTP request or WebSocket handshake
@@ -78,22 +70,27 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
* @param body the deserialized content of the GraphQL request
* @param id an identifier for the GraphQL request
* @param locale the locale from the HTTP request, if any
* @since 1.2.5
*/
public WebGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
Map<String, Object> attributes, GraphQlRequest body, String id, @Nullable Locale locale) {
this(uri, headers, cookies, attributes, body.getDocument(),
body.getOperationName(), body.getVariables(), body.getExtensions(), id, locale);
}
/**
* Variant of {@link #WebGraphQlRequest(URI, HttpHeaders, MultiValueMap, Map, GraphQlRequest, String, Locale)}
* with a Map for the request body.
* @since 1.1.3
*/
public WebGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
Map<String, Object> attributes, Map<String, Object> body, String id, @Nullable Locale locale) {
super(getQuery(body), getOperation(body),
this(uri, headers, cookies, attributes, getQuery(body), getOperation(body),
getMap(VARIABLES_KEY, body), getMap(EXTENSIONS_KEY, body), id, locale);
Assert.notNull(uri, "URI is required'");
Assert.notNull(headers, "HttpHeaders is required'");
this.uri = UriComponentsBuilder.fromUri(uri).build(true);
this.headers = headers;
this.cookies = (cookies != null ? CollectionUtils.unmodifiableMultiValueMap(cookies) : EMPTY_COOKIES);
this.attributes = Collections.unmodifiableMap(attributes);
}
private static String getQuery(Map<String, Object> body) {
@@ -123,6 +120,33 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
return (Map<String, Object>) value;
}
/**
* Create an instance.
* @deprecated as of 1.1.3 in favor of
* {@link #WebGraphQlRequest(URI, HttpHeaders, MultiValueMap, Map, GraphQlRequest, String, Locale)}
*/
@Deprecated(since = "1.1.3", forRemoval = true)
public WebGraphQlRequest(URI uri, HttpHeaders headers, Map<String, Object> body, String id, @Nullable Locale locale) {
this(uri, headers, null, Collections.emptyMap(), body, id, locale);
}
private WebGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
Map<String, Object> attributes, String document, @Nullable String operationName,
@Nullable Map<String, Object> variables, @Nullable Map<String, Object> extensions,
String id, @Nullable Locale locale) {
super(document, operationName, variables, extensions, id, locale);
Assert.notNull(uri, "URI is required'");
Assert.notNull(headers, "HttpHeaders is required'");
this.uri = UriComponentsBuilder.fromUri(uri).build(true);
this.headers = headers;
this.cookies = (cookies != null ? CollectionUtils.unmodifiableMultiValueMap(cookies) : EMPTY_COOKIES);
this.attributes = Collections.unmodifiableMap(attributes);
}
/**
* Return the URL for the HTTP request or WebSocket handshake.

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2002-2024 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.server.support;
import java.util.Map;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.lang.Nullable;
import org.springframework.web.server.ServerWebInputException;
/**
* {@link GraphQlRequest} for deserialization from a request.
*
* @author Rossen Stoyanchev
* @since 1.2.5
*/
public class SerializableGraphQlRequest implements GraphQlRequest {
@Nullable
private String query;
@Nullable
private String operationName;
@Nullable
private Map<String, Object> variables;
@Nullable
private Map<String, Object> extensions;
public void setQuery(String query) {
this.query = query;
}
@Nullable
public String getQuery() {
return this.query;
}
public void setOperationName(@Nullable String operationName) {
this.operationName = operationName;
}
@Nullable
@Override
public String getOperationName() {
return this.operationName;
}
public void setVariables(Map<String, Object> variables) {
this.variables = variables;
}
@Nullable
@Override
public Map<String, Object> getVariables() {
return this.variables;
}
public void setExtensions(Map<String, Object> extensions) {
this.extensions = extensions;
}
@Nullable
@Override
public Map<String, Object> getExtensions() {
return this.extensions;
}
@Override
public String getDocument() {
if (this.query == null) {
throw new ServerWebInputException("No 'query'");
}
return this.query;
}
@Override
public Map<String, Object> toMap() {
throw new UnsupportedOperationException();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 the original author or authors.
* Copyright 2020-2024 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.
@@ -27,6 +27,7 @@ import reactor.core.publisher.Mono;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.graphql.server.WebGraphQlHandler;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.support.SerializableGraphQlRequest;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.server.ServerRequest;
@@ -71,7 +72,7 @@ public class GraphQlHttpHandler {
* @return the HTTP response
*/
public Mono<ServerResponse> handleRequest(ServerRequest serverRequest) {
return serverRequest.bodyToMono(MAP_PARAMETERIZED_TYPE_REF)
return serverRequest.bodyToMono(SerializableGraphQlRequest.class)
.flatMap(body -> {
WebGraphQlRequest graphQlRequest = new WebGraphQlRequest(
serverRequest.uri(), serverRequest.headers().asHttpHeaders(),

View File

@@ -30,8 +30,10 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.server.WebGraphQlHandler;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.support.SerializableGraphQlRequest;
import org.springframework.http.HttpCookie;
import org.springframework.http.MediaType;
import org.springframework.util.AlternativeJdkIdGenerator;
@@ -135,9 +137,9 @@ public class GraphQlHttpHandler {
return target;
}
private static Map<String, Object> readBody(ServerRequest request) throws ServletException {
private static GraphQlRequest readBody(ServerRequest request) throws ServletException {
try {
return request.body(MAP_PARAMETERIZED_TYPE_REF);
return request.body(SerializableGraphQlRequest.class);
}
catch (IOException ex) {
throw new ServerWebInputException("I/O error while reading request body", null, ex);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -49,14 +49,13 @@ import org.springframework.graphql.ExecutionGraphQlResponse;
import org.springframework.graphql.GraphQlSetup;
import org.springframework.graphql.ResponseHelper;
import org.springframework.graphql.data.GraphQlRepository;
import org.springframework.graphql.data.pagination.ConnectionFieldTypeVisitor;
import org.springframework.graphql.data.query.QuerydslDataFetcher.Builder;
import org.springframework.graphql.data.query.QuerydslDataFetcher.QuerydslBuilderCustomizer;
import org.springframework.graphql.execution.ConnectionTypeDefinitionConfigurer;
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import org.springframework.graphql.server.WebGraphQlHandler;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
@@ -378,7 +377,7 @@ class QuerydslDataFetcherTests {
private WebGraphQlRequest request(String query) {
return new WebGraphQlRequest(
URI.create("/"), new HttpHeaders(), null, Collections.emptyMap(),
Collections.singletonMap("query", query), "1", Locale.ENGLISH);
new DefaultGraphQlRequest(query), "1", Locale.ENGLISH);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -51,6 +51,7 @@ import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import org.springframework.graphql.server.WebGraphQlHandler;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
@@ -262,7 +263,7 @@ class QueryByExampleDataFetcherJpaTests {
private WebGraphQlRequest request(String query) {
return new WebGraphQlRequest(
URI.create("/"), new HttpHeaders(), null, Collections.emptyMap(),
Collections.singletonMap("query", query), "1", null);
new DefaultGraphQlRequest(query), "1", null);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -45,16 +45,15 @@ import org.springframework.data.repository.query.QueryByExampleExecutor;
import org.springframework.graphql.BookSource;
import org.springframework.graphql.GraphQlSetup;
import org.springframework.graphql.ResponseHelper;
import org.springframework.graphql.data.pagination.ConnectionFieldTypeVisitor;
import org.springframework.graphql.data.query.QueryByExampleDataFetcher;
import org.springframework.graphql.data.query.ScrollPositionCursorStrategy;
import org.springframework.graphql.data.query.ScrollSubrange;
import org.springframework.graphql.data.query.WindowConnectionAdapter;
import org.springframework.graphql.execution.ConnectionTypeDefinitionConfigurer;
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import org.springframework.graphql.server.WebGraphQlHandler;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@@ -242,7 +241,7 @@ class QueryByExampleDataFetcherMongoDbTests {
private WebGraphQlRequest request(String query) {
return new WebGraphQlRequest(
URI.create("/"), new HttpHeaders(), null, Collections.emptyMap(),
Collections.singletonMap("query", query), "1", null);
new DefaultGraphQlRequest(query), "1", null);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -52,6 +52,7 @@ import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import org.springframework.graphql.server.WebGraphQlHandler;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@@ -213,7 +214,7 @@ class QueryByExampleDataFetcherReactiveMongoDbTests {
private WebGraphQlRequest request(String query) {
return new WebGraphQlRequest(
URI.create("/"), new HttpHeaders(), null, Collections.emptyMap(),
Collections.singletonMap("query", query), "1", null);
new DefaultGraphQlRequest(query), "1", null);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -16,11 +16,26 @@
package org.springframework.graphql.data.query.neo4j;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import graphql.schema.DataFetcher;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
@@ -40,23 +55,10 @@ import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import org.springframework.graphql.server.WebGraphQlHandler;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.any;
@@ -241,7 +243,7 @@ class QueryByExampleDataFetcherNeo4jTests {
private WebGraphQlRequest request(String query) {
return new WebGraphQlRequest(
URI.create("/"), new HttpHeaders(), null, Collections.emptyMap(),
Collections.singletonMap("query", query), "1", null);
new DefaultGraphQlRequest(query), "1", null);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -16,6 +16,13 @@
package org.springframework.graphql.data.query.neo4j;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import graphql.schema.DataFetcher;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -23,6 +30,13 @@ import org.neo4j.cypherdsl.core.renderer.Dialect;
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
@@ -42,22 +56,10 @@ import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import org.springframework.graphql.server.WebGraphQlHandler;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@@ -225,7 +227,7 @@ class QueryByExampleDataFetcherReactiveNeo4jDbTests {
private WebGraphQlRequest request(String query) {
return new WebGraphQlRequest(
URI.create("/"), new HttpHeaders(), null, Collections.emptyMap(),
Collections.singletonMap("query", query), "1", null);
new DefaultGraphQlRequest(query), "1", null);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -32,6 +32,7 @@ import org.springframework.graphql.TestThreadLocalAccessor;
import org.springframework.graphql.execution.DataFetcherExceptionResolver;
import org.springframework.graphql.execution.DataFetcherExceptionResolverAdapter;
import org.springframework.graphql.execution.ErrorType;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.http.HttpHeaders;
import static org.assertj.core.api.Assertions.assertThat;
@@ -43,7 +44,7 @@ public class WebGraphQlHandlerTests {
private static final WebGraphQlRequest webInput = new WebGraphQlRequest(
URI.create("https://abc.org"), new HttpHeaders(), null, Collections.emptyMap(),
Collections.singletonMap("query", "{ greeting }"), "1", null);
new DefaultGraphQlRequest("{ greeting }"), "1", null);
private final GraphQlSetup graphQlSetup = GraphQlSetup.schemaContent("type Query { greeting: String }");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -30,6 +30,7 @@ import reactor.core.scheduler.Schedulers;
import org.springframework.graphql.ExecutionGraphQlRequest;
import org.springframework.graphql.ExecutionGraphQlResponse;
import org.springframework.graphql.support.DefaultExecutionGraphQlResponse;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.http.HttpHeaders;
import static org.assertj.core.api.Assertions.assertThat;
@@ -41,7 +42,7 @@ public class WebGraphQlInterceptorTests {
private static final WebGraphQlRequest webRequest = new WebGraphQlRequest(
URI.create("http://abc.org"), new HttpHeaders(), null, Collections.emptyMap(),
Collections.singletonMap("query", "{ notUsed }"), "1", null);
new DefaultGraphQlRequest("{ notUsed }"), "1", null);
@Test
void interceptorOrder() {

View File

@@ -1,56 +0,0 @@
/*
* Copyright 2002-2023 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.server;
import java.net.URI;
import java.util.Collections;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.server.ServerWebInputException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Unit tests for {@link WebGraphQlRequest}.
*
* @author Rossen Stoyanchev
*/
public class WebGraphQlRequestTests {
@Test // gh-726
void invalidBody() {
testInvalidBody(Map.of());
testInvalidBody(Map.of("query", Collections.emptyMap()));
testInvalidBody(Map.of("query", "query { foo }", "operationName", Collections.emptyMap()));
testInvalidBody(Map.of("query", "query { foo }", "variables", "not-a-map"));
testInvalidBody(Map.of("query", "query { foo }", "extensions", "not-a-map"));
}
private void testInvalidBody(Map<String, Object> body) {
assertThatThrownBy(() ->
new WebGraphQlRequest(
URI.create("/graphql"), new HttpHeaders(), new LinkedMultiValueMap<>(),
Collections.emptyMap(), body, "1", null))
.isInstanceOf(ServerWebInputException.class);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@@ -18,14 +18,15 @@ package org.springframework.graphql.server.webflux;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlSetup;
import org.springframework.graphql.server.support.SerializableGraphQlRequest;
import org.springframework.http.MediaType;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter;
@@ -55,8 +56,9 @@ public class GraphQlHttpHandlerTests {
MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/")
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.ALL).build();
String document = "{greeting}";
MockServerHttpResponse httpResponse = handleRequest(
httpRequest, this.greetingHandler, Collections.singletonMap("query", "{greeting}"));
httpRequest, this.greetingHandler, initRequest(document));
assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
}
@@ -67,7 +69,7 @@ public class GraphQlHttpHandlerTests {
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build();
MockServerHttpResponse httpResponse = handleRequest(
httpRequest, this.greetingHandler, Collections.singletonMap("query", "{greeting}"));
httpRequest, this.greetingHandler, initRequest("{greeting}"));
assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE);
}
@@ -78,7 +80,7 @@ public class GraphQlHttpHandlerTests {
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).build();
MockServerHttpResponse httpResponse = handleRequest(
httpRequest, this.greetingHandler, Collections.singletonMap("query", "{greeting}"));
httpRequest, this.greetingHandler, initRequest("{greeting}"));
assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
}
@@ -94,7 +96,7 @@ public class GraphQlHttpHandlerTests {
.acceptLanguageAsLocales(Locale.FRENCH).build();
MockServerHttpResponse httpResponse = handleRequest(
httpRequest, handler, Collections.singletonMap("query", "{greeting}"));
httpRequest, handler, initRequest("{greeting}"));
assertThat(httpResponse.getBodyAsString().block())
.isEqualTo("{\"data\":{\"greeting\":\"Hello in fr\"}}");
@@ -110,15 +112,21 @@ public class GraphQlHttpHandlerTests {
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build();
MockServerHttpResponse httpResponse = handleRequest(
httpRequest, handler, Collections.singletonMap("query", "{showId}"));
httpRequest, handler, initRequest("{showId}"));
DocumentContext document = JsonPath.parse(httpResponse.getBodyAsString().block());
String id = document.read("data.showId", String.class);
assertThat(id).isEqualTo(httpRequest.getId());
}
private static SerializableGraphQlRequest initRequest(String document) {
SerializableGraphQlRequest request = new SerializableGraphQlRequest();
request.setQuery(document);
return request;
}
private MockServerHttpResponse handleRequest(
MockServerHttpRequest httpRequest, GraphQlHttpHandler handler, Map<String, String> body) {
MockServerHttpRequest httpRequest, GraphQlHttpHandler handler, GraphQlRequest body) {
MockServerWebExchange exchange = MockServerWebExchange.from(httpRequest);
@@ -127,7 +135,7 @@ public class GraphQlHttpHandlerTests {
.uri(((ServerWebExchange) exchange).getRequest().getURI())
.method(((ServerWebExchange) exchange).getRequest().getMethod())
.headers(((ServerWebExchange) exchange).getRequest().getHeaders())
.body(Mono.just((Object) body));
.body(Mono.just(body));
handler.handleRequest(serverRequest)
.flatMap(response -> response.writeTo(exchange, new DefaultContext()))