diff --git a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/autoconfigure/SpqrMvcAutoConfiguration.java b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/autoconfigure/SpqrMvcAutoConfiguration.java index ecd862b..d942d37 100644 --- a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/autoconfigure/SpqrMvcAutoConfiguration.java +++ b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/autoconfigure/SpqrMvcAutoConfiguration.java @@ -1,5 +1,6 @@ package io.leangen.graphql.spqr.spring.autoconfigure; +import com.fasterxml.jackson.databind.ObjectMapper; import graphql.GraphQL; import graphql.schema.GraphQLSchema; import io.leangen.graphql.spqr.spring.web.GraphQLController; @@ -40,8 +41,8 @@ public GraphQLServletExecutor graphQLExecutor(ServletContextFactory contextFacto @ConditionalOnProperty(name = "graphql.spqr.http.enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnMissingBean(GraphQLController.class) @ConditionalOnBean(GraphQLSchema.class) - public DefaultGraphQLController graphQLController(GraphQL graphQL, GraphQLServletExecutor executor) { - return new DefaultGraphQLController(graphQL, executor); + public DefaultGraphQLController graphQLController(GraphQL graphQL, GraphQLServletExecutor executor, ObjectMapper objectMapper) { + return new DefaultGraphQLController(graphQL, executor, objectMapper); } @Bean diff --git a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/autoconfigure/SpqrReactiveAutoConfiguration.java b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/autoconfigure/SpqrReactiveAutoConfiguration.java index 9376217..eaa06e2 100644 --- a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/autoconfigure/SpqrReactiveAutoConfiguration.java +++ b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/autoconfigure/SpqrReactiveAutoConfiguration.java @@ -1,15 +1,16 @@ package io.leangen.graphql.spqr.spring.autoconfigure; +import com.fasterxml.jackson.databind.ObjectMapper; import graphql.GraphQL; import graphql.schema.GraphQLSchema; import io.leangen.graphql.module.Module; import io.leangen.graphql.spqr.spring.autoconfigure.reactive.FluxAdapter; import io.leangen.graphql.spqr.spring.autoconfigure.reactive.MonoAdapter; import io.leangen.graphql.spqr.spring.web.GraphQLController; -import io.leangen.graphql.spqr.spring.web.reactive.GraphQLReactiveExecutor; import io.leangen.graphql.spqr.spring.web.GuiController; -import io.leangen.graphql.spqr.spring.web.reactive.DefaultGraphQLExecutor; import io.leangen.graphql.spqr.spring.web.reactive.DefaultGraphQLController; +import io.leangen.graphql.spqr.spring.web.reactive.DefaultGraphQLExecutor; +import io.leangen.graphql.spqr.spring.web.reactive.GraphQLReactiveExecutor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -53,8 +54,8 @@ public GraphQLReactiveExecutor graphQLExecutor(ReactiveContextFactory contextFac @ConditionalOnProperty(name = "graphql.spqr.http.enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnMissingBean(GraphQLController.class) @ConditionalOnBean(GraphQLSchema.class) - public DefaultGraphQLController graphQLController(GraphQL graphQL, GraphQLReactiveExecutor executor) { - return new DefaultGraphQLController(graphQL, executor); + public DefaultGraphQLController graphQLController(GraphQL graphQL, GraphQLReactiveExecutor executor, ObjectMapper objectMapper) { + return new DefaultGraphQLController(graphQL, executor, objectMapper); } @Bean diff --git a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/GraphQLController.java b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/GraphQLController.java index a14bcf7..6011501 100644 --- a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/GraphQLController.java +++ b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/GraphQLController.java @@ -1,29 +1,27 @@ package io.leangen.graphql.spqr.spring.web; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; import graphql.GraphQL; import io.leangen.graphql.spqr.spring.web.dto.GraphQLRequest; import org.springframework.http.MediaType; import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Map; +import org.springframework.web.bind.annotation.*; @RestController public abstract class GraphQLController { protected final GraphQL graphQL; protected final GraphQLExecutor executor; + private ObjectMapper objectMapper; - public GraphQLController(GraphQL graphQL, GraphQLExecutor executor) { + public GraphQLController(GraphQL graphQL, GraphQLExecutor executor, ObjectMapper objectMapper) { this.graphQL = graphQL; this.executor = executor; + this.objectMapper = objectMapper; } @PostMapping( @@ -33,11 +31,14 @@ public GraphQLController(GraphQL graphQL, GraphQLExecutor executor) { ) @ResponseBody public Object executeJsonPost(@RequestBody GraphQLRequest requestBody, - GraphQLRequest requestParams, - R request) { - String query = requestParams.getQuery() == null ? requestBody.getQuery() : requestParams.getQuery(); - String operationName = requestParams.getOperationName() == null ? requestBody.getOperationName() : requestParams.getOperationName(); - Map variables = requestParams.getVariables() == null ? requestBody.getVariables() : requestParams.getVariables(); + @RequestParam(value = "query", required = false) String requestQuery, + @RequestParam(value = "operationName", required = false) String requestOperationName, + @RequestParam(value = "variables", required = false) String variablesJsonString, + R request) throws IOException { + String query = requestQuery == null ? requestBody.getQuery() : requestQuery; + String operationName = requestOperationName == null ? requestBody.getOperationName() : requestOperationName; + //noinspection unchecked + Map variables = variablesJsonString == null ? requestBody.getVariables() : objectMapper.readValue(variablesJsonString, Map.class); return executor.execute(graphQL, new GraphQLRequest(query, operationName, variables), request); } @@ -80,7 +81,12 @@ public Object executeFormPost(@RequestParam Map queryParams, headers = "Connection!=Upgrade" ) @ResponseBody - public Object executeGet(GraphQLRequest graphQLRequest, R request) { - return executor.execute(graphQL, graphQLRequest, request); + public Object executeGet(@RequestParam(value = "query") String requestQuery, + @RequestParam(value = "operationName", required = false) String requestOperationName, + @RequestParam(value = "variables", required = false) String variablesJsonString, + R request) throws IOException { + //noinspection unchecked + Map variables = variablesJsonString == null ? Collections.emptyMap() : objectMapper.readValue(variablesJsonString, Map.class); + return executor.execute(graphQL, new GraphQLRequest(requestQuery, requestOperationName, variables), request); } } diff --git a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/reactive/DefaultGraphQLController.java b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/reactive/DefaultGraphQLController.java index e6b2f30..da9ecad 100644 --- a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/reactive/DefaultGraphQLController.java +++ b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/reactive/DefaultGraphQLController.java @@ -1,5 +1,6 @@ package io.leangen.graphql.spqr.spring.web.reactive; +import com.fasterxml.jackson.databind.ObjectMapper; import graphql.GraphQL; import io.leangen.graphql.spqr.spring.web.GraphQLController; import org.springframework.beans.factory.annotation.Autowired; @@ -12,7 +13,7 @@ public class DefaultGraphQLController extends GraphQLController { @Autowired - public DefaultGraphQLController(GraphQL graphQL, GraphQLReactiveExecutor executor) { - super(graphQL, executor); + public DefaultGraphQLController(GraphQL graphQL, GraphQLReactiveExecutor executor, ObjectMapper objectMapper) { + super(graphQL, executor, objectMapper); } } diff --git a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/servlet/DefaultGraphQLController.java b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/servlet/DefaultGraphQLController.java index bc3074b..0161ac2 100644 --- a/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/servlet/DefaultGraphQLController.java +++ b/graphql-spqr-spring-boot-autoconfigure/src/main/java/io/leangen/graphql/spqr/spring/web/servlet/DefaultGraphQLController.java @@ -1,5 +1,6 @@ package io.leangen.graphql.spqr.spring.web.servlet; +import com.fasterxml.jackson.databind.ObjectMapper; import graphql.GraphQL; import io.leangen.graphql.spqr.spring.web.GraphQLController; import org.springframework.beans.factory.annotation.Autowired; @@ -12,7 +13,7 @@ public class DefaultGraphQLController extends GraphQLController { @Autowired - public DefaultGraphQLController(GraphQL graphQL, GraphQLServletExecutor executor) { - super(graphQL, executor); + public DefaultGraphQLController(GraphQL graphQL, GraphQLServletExecutor executor, ObjectMapper objectMapper) { + super(graphQL, executor, objectMapper); } } diff --git a/graphql-spqr-spring-boot-autoconfigure/src/test/java/io/leangen/graphql/spqr/spring/test/ResolverBuilder_TestConfig.java b/graphql-spqr-spring-boot-autoconfigure/src/test/java/io/leangen/graphql/spqr/spring/test/ResolverBuilder_TestConfig.java index 5068bfe..cebff90 100644 --- a/graphql-spqr-spring-boot-autoconfigure/src/test/java/io/leangen/graphql/spqr/spring/test/ResolverBuilder_TestConfig.java +++ b/graphql-spqr-spring-boot-autoconfigure/src/test/java/io/leangen/graphql/spqr/spring/test/ResolverBuilder_TestConfig.java @@ -1,7 +1,11 @@ package io.leangen.graphql.spqr.spring.test; +import java.lang.reflect.Method; +import java.util.Arrays; + import io.leangen.graphql.ExtensionProvider; import io.leangen.graphql.GeneratorConfiguration; +import io.leangen.graphql.annotations.GraphQLArgument; import io.leangen.graphql.annotations.GraphQLQuery; import io.leangen.graphql.metadata.strategy.query.BeanResolverBuilder; import io.leangen.graphql.metadata.strategy.query.PublicResolverBuilder; @@ -13,9 +17,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; - -import java.lang.reflect.Method; -import java.util.Arrays; +import org.springframework.web.multipart.MultipartFile; @Configuration public class ResolverBuilder_TestConfig { @@ -41,11 +43,16 @@ protected boolean isQuery(Method method, ResolverBuilderParams params) { @Component("annotatedOperationSourceBean") @GraphQLApi - private static class AnnotatedOperationSourceBean { + public static class AnnotatedOperationSourceBean { @GraphQLQuery(name = "greetingFromAnnotatedSource_wiredAsComponent") public String getGreeting(){ return "Hello world !"; } + + @GraphQLQuery(name = "echo") + public String echo(@GraphQLArgument(name = "content") String content) { + return content; + } } @Bean diff --git a/graphql-spqr-spring-boot-autoconfigure/src/test/java/io/leangen/graphql/spqr/spring/web/GraphQLControllerTest.java b/graphql-spqr-spring-boot-autoconfigure/src/test/java/io/leangen/graphql/spqr/spring/web/GraphQLControllerTest.java index 12d2543..5fcc43a 100644 --- a/graphql-spqr-spring-boot-autoconfigure/src/test/java/io/leangen/graphql/spqr/spring/web/GraphQLControllerTest.java +++ b/graphql-spqr-spring-boot-autoconfigure/src/test/java/io/leangen/graphql/spqr/spring/web/GraphQLControllerTest.java @@ -1,5 +1,8 @@ package io.leangen.graphql.spqr.spring.web; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + import io.leangen.graphql.spqr.spring.autoconfigure.SpqrAutoConfiguration; import io.leangen.graphql.spqr.spring.autoconfigure.SpqrMvcAutoConfiguration; import io.leangen.graphql.spqr.spring.test.ResolverBuilder_TestConfig; @@ -14,9 +17,6 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -109,14 +109,37 @@ public void defaultControllerTest_POST_applicationJson_INVALID() throws Exceptio @Test public void defaultControllerTest_POST_applicationJson_overridingQueryParams() throws Exception { mockMvc.perform( - post("/"+apiContext) - .param("query","{greetingFromBeanSource_wiredAsComponent_byAnnotation}") + post("/" + apiContext) + .param("query", "{greetingFromBeanSource_wiredAsComponent_byAnnotation}") .contentType(MediaType.APPLICATION_JSON_UTF8) .content("{\"query\":\"{INVALID_QUERY}\",\"variables\":null,\"operationName\":null}")) .andExpect(status().isOk()) .andExpect(content().string(containsString("Hello world"))); } + @Test + public void defaultControllerTest_GET_with_variables() throws Exception { + mockMvc.perform( + get("/" + apiContext) + .param("query", "query Echo($contentInput: String){ echo(content: $contentInput)}") + .param("variables", "{\"contentInput\": \"Hello world\"}") + ) + .andExpect(status().isOk()) + .andExpect(content().json("{\"data\":{\"echo\":\"Hello world\"}}", true)); + } + + @Test + public void defaultControllerTest_POST_with_variables() throws Exception { + mockMvc.perform( + post("/" + apiContext) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content("{\"query\":\"{INVALID_QUERY}\",\"variables\":{\"contentInput\": \"Hello world2\"},\"operationName\":null}") + .param("query", "query Echo($contentInput: String){ echo(content: $contentInput)}") + .param("variables", "{\"contentInput\": \"Hello world1\"}")) + .andExpect(status().isOk()) + .andExpect(content().json("{\"data\":{\"echo\":\"Hello world1\"}}", true)); + } + @Test public void defaultControllerTest_POST_formUrlEncoded_INVALID() throws Exception { mockMvc.perform(