Polish GraphQL auto-configuration
This commit is contained in:
parent
ce08b519b1
commit
a05903b9d1
|
@ -19,11 +19,13 @@ package org.springframework.boot.autoconfigure.graphql;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import graphql.GraphQL;
|
||||
import graphql.execution.instrumentation.Instrumentation;
|
||||
import graphql.schema.idl.RuntimeWiring.Builder;
|
||||
import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -67,29 +69,49 @@ public class GraphQlAutoConfiguration {
|
|||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQlSource graphQlSource(ResourcePatternResolver resourcePatternResolver, GraphQlProperties properties,
|
||||
ObjectProvider<DataFetcherExceptionResolver> exceptionResolversProvider,
|
||||
ObjectProvider<Instrumentation> instrumentationsProvider,
|
||||
ObjectProvider<RuntimeWiringConfigurer> wiringConfigurers,
|
||||
ObjectProvider<DataFetcherExceptionResolver> exceptionResolvers,
|
||||
ObjectProvider<Instrumentation> instrumentations, ObjectProvider<RuntimeWiringConfigurer> wiringConfigurers,
|
||||
ObjectProvider<GraphQlSourceBuilderCustomizer> sourceCustomizers) {
|
||||
|
||||
List<Resource> schemaResources = resolveSchemaResources(resourcePatternResolver,
|
||||
properties.getSchema().getLocations(), properties.getSchema().getFileExtensions());
|
||||
GraphQlSource.Builder builder = GraphQlSource.builder()
|
||||
.schemaResources(schemaResources.toArray(new Resource[0]))
|
||||
.exceptionResolvers(exceptionResolversProvider.orderedStream().collect(Collectors.toList()))
|
||||
.instrumentation(instrumentationsProvider.orderedStream().collect(Collectors.toList()));
|
||||
String[] schemaLocations = properties.getSchema().getLocations();
|
||||
Resource[] schemaResources = resolveSchemaResources(resourcePatternResolver, schemaLocations,
|
||||
properties.getSchema().getFileExtensions());
|
||||
GraphQlSource.Builder builder = GraphQlSource.builder().schemaResources(schemaResources)
|
||||
.exceptionResolvers(toList(exceptionResolvers)).instrumentation(toList(instrumentations));
|
||||
if (!properties.getSchema().getIntrospection().isEnabled()) {
|
||||
builder.configureRuntimeWiring((wiring) -> wiring
|
||||
.fieldVisibility(NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY));
|
||||
builder.configureRuntimeWiring(this::enableIntrospection);
|
||||
}
|
||||
wiringConfigurers.orderedStream().forEach(builder::configureRuntimeWiring);
|
||||
sourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
try {
|
||||
return builder.build();
|
||||
}
|
||||
catch (MissingSchemaException exc) {
|
||||
throw new InvalidSchemaLocationsException(properties.getSchema().getLocations(), resourcePatternResolver,
|
||||
exc);
|
||||
catch (MissingSchemaException ex) {
|
||||
throw new InvalidSchemaLocationsException(schemaLocations, resourcePatternResolver, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Builder enableIntrospection(Builder wiring) {
|
||||
return wiring.fieldVisibility(NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY);
|
||||
}
|
||||
|
||||
private Resource[] resolveSchemaResources(ResourcePatternResolver resolver, String[] locations,
|
||||
String[] extensions) {
|
||||
List<Resource> resources = new ArrayList<>();
|
||||
for (String location : locations) {
|
||||
for (String extension : extensions) {
|
||||
resources.addAll(resolveSchemaResources(resolver, location + "*" + extension));
|
||||
}
|
||||
}
|
||||
return resources.toArray(new Resource[0]);
|
||||
}
|
||||
|
||||
private List<Resource> resolveSchemaResources(ResourcePatternResolver resolver, String pattern) {
|
||||
try {
|
||||
return Arrays.asList(resolver.getResources(pattern));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
logger.debug("Could not resolve schema location: '" + pattern + "'", ex);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,21 +137,8 @@ public class GraphQlAutoConfiguration {
|
|||
return annotatedControllerConfigurer;
|
||||
}
|
||||
|
||||
private List<Resource> resolveSchemaResources(ResourcePatternResolver resolver, String[] schemaLocations,
|
||||
String[] fileExtensions) {
|
||||
List<Resource> schemaResources = new ArrayList<>();
|
||||
for (String location : schemaLocations) {
|
||||
for (String extension : fileExtensions) {
|
||||
String resourcePattern = location + "*" + extension;
|
||||
try {
|
||||
schemaResources.addAll(Arrays.asList(resolver.getResources(resourcePattern)));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
logger.debug("Could not resolve schema location: '" + resourcePattern + "'", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return schemaResources;
|
||||
private <T> List<T> toList(ObjectProvider<T> provider) {
|
||||
return provider.orderedStream().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.List;
|
|||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.convert.DurationUnit;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
||||
|
@ -73,7 +72,6 @@ public class GraphQlCorsProperties {
|
|||
/**
|
||||
* Whether credentials are supported. When not set, credentials are not supported.
|
||||
*/
|
||||
@Nullable
|
||||
private Boolean allowCredentials;
|
||||
|
||||
/**
|
||||
|
@ -123,7 +121,6 @@ public class GraphQlCorsProperties {
|
|||
this.exposedHeaders = exposedHeaders;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getAllowCredentials() {
|
||||
return this.allowCredentials;
|
||||
}
|
||||
|
@ -140,7 +137,6 @@ public class GraphQlCorsProperties {
|
|||
this.maxAge = maxAge;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CorsConfiguration toCorsConfiguration() {
|
||||
if (CollectionUtils.isEmpty(this.allowedOrigins) && CollectionUtils.isEmpty(this.allowedOriginPatterns)) {
|
||||
return null;
|
||||
|
|
|
@ -20,8 +20,8 @@ import org.springframework.graphql.execution.GraphQlSource;
|
|||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize properties of
|
||||
* {@link org.springframework.graphql.execution.GraphQlSource.Builder} whilst retaining
|
||||
* default auto-configuration.
|
||||
* {@link org.springframework.graphql.execution.GraphQlSource.Builder Builder} whilst
|
||||
* retaining default auto-configuration.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 2.7.0
|
||||
|
@ -30,7 +30,8 @@ import org.springframework.graphql.execution.GraphQlSource;
|
|||
public interface GraphQlSourceBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link GraphQlSource.Builder} instance.
|
||||
* Customize the {@link org.springframework.graphql.execution.GraphQlSource.Builder
|
||||
* Builder} instance.
|
||||
* @param builder builder the builder to customize
|
||||
*/
|
||||
void customize(GraphQlSource.Builder builder);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.boot.autoconfigure.graphql.data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import graphql.GraphQL;
|
||||
|
||||
|
@ -52,19 +51,10 @@ import org.springframework.graphql.execution.GraphQlSource;
|
|||
public class GraphQlQueryByExampleAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public GraphQlSourceBuilderCustomizer queryByExampleRegistrar(
|
||||
ObjectProvider<QueryByExampleExecutor<?>> executorsProvider,
|
||||
ObjectProvider<ReactiveQueryByExampleExecutor<?>> reactiveExecutorsProvider) {
|
||||
|
||||
return (builder) -> {
|
||||
List<QueryByExampleExecutor<?>> executors = executorsProvider.stream().collect(Collectors.toList());
|
||||
List<ReactiveQueryByExampleExecutor<?>> reactiveExecutors = reactiveExecutorsProvider.stream()
|
||||
.collect(Collectors.toList());
|
||||
if (!executors.isEmpty()) {
|
||||
builder.configureRuntimeWiring(
|
||||
QueryByExampleDataFetcher.autoRegistrationConfigurer(executors, reactiveExecutors));
|
||||
}
|
||||
};
|
||||
public GraphQlSourceBuilderCustomizer queryByExampleRegistrar(ObjectProvider<QueryByExampleExecutor<?>> executors,
|
||||
ObjectProvider<ReactiveQueryByExampleExecutor<?>> reactiveExecutors) {
|
||||
return new GraphQlQuerydslSourceBuilderCustomizer<>(QueryByExampleDataFetcher::autoRegistrationConfigurer,
|
||||
executors, reactiveExecutors);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.boot.autoconfigure.graphql.data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import graphql.GraphQL;
|
||||
|
||||
|
@ -53,19 +52,10 @@ import org.springframework.graphql.execution.GraphQlSource;
|
|||
public class GraphQlQuerydslAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public GraphQlSourceBuilderCustomizer querydslRegistrar(
|
||||
ObjectProvider<QuerydslPredicateExecutor<?>> executorsProvider,
|
||||
ObjectProvider<ReactiveQuerydslPredicateExecutor<?>> reactiveExecutorsProvider) {
|
||||
|
||||
return (builder) -> {
|
||||
List<QuerydslPredicateExecutor<?>> executors = executorsProvider.stream().collect(Collectors.toList());
|
||||
if (!executors.isEmpty()) {
|
||||
List<ReactiveQuerydslPredicateExecutor<?>> reactiveExecutors = reactiveExecutorsProvider.stream()
|
||||
.collect(Collectors.toList());
|
||||
builder.configureRuntimeWiring(
|
||||
QuerydslDataFetcher.autoRegistrationConfigurer(executors, reactiveExecutors));
|
||||
}
|
||||
};
|
||||
public GraphQlSourceBuilderCustomizer querydslRegistrar(ObjectProvider<QuerydslPredicateExecutor<?>> executors,
|
||||
ObjectProvider<ReactiveQuerydslPredicateExecutor<?>> reactiveExecutors) {
|
||||
return new GraphQlQuerydslSourceBuilderCustomizer<>(QuerydslDataFetcher::autoRegistrationConfigurer, executors,
|
||||
reactiveExecutors);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2012-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.boot.autoconfigure.graphql.data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
|
||||
import org.springframework.graphql.execution.GraphQlSource.Builder;
|
||||
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
|
||||
|
||||
/**
|
||||
* {@link GraphQlSourceBuilderCustomizer} to apply auto-configured QueryDSL
|
||||
* {@link RuntimeWiringConfigurer RuntimeWiringConfigurers}.
|
||||
*
|
||||
* @param <E> the executor type
|
||||
* @param <R> the reactive executor type
|
||||
* @author Phillip Webb
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class GraphQlQuerydslSourceBuilderCustomizer<E, R> implements GraphQlSourceBuilderCustomizer {
|
||||
|
||||
private final BiFunction<List<E>, List<R>, RuntimeWiringConfigurer> wiringConfigurerFactory;
|
||||
|
||||
private final List<E> executors;
|
||||
|
||||
private final List<R> reactiveExecutors;
|
||||
|
||||
GraphQlQuerydslSourceBuilderCustomizer(
|
||||
BiFunction<List<E>, List<R>, RuntimeWiringConfigurer> wiringConfigurerFactory, ObjectProvider<E> executors,
|
||||
ObjectProvider<R> reactiveExecutors) {
|
||||
this(wiringConfigurerFactory, toList(executors), toList(reactiveExecutors));
|
||||
}
|
||||
|
||||
GraphQlQuerydslSourceBuilderCustomizer(
|
||||
BiFunction<List<E>, List<R>, RuntimeWiringConfigurer> wiringConfigurerFactory, List<E> executors,
|
||||
List<R> reactiveExecutors) {
|
||||
this.wiringConfigurerFactory = wiringConfigurerFactory;
|
||||
this.executors = executors;
|
||||
this.reactiveExecutors = reactiveExecutors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(Builder builder) {
|
||||
if (!this.executors.isEmpty() || !this.reactiveExecutors.isEmpty()) {
|
||||
builder.configureRuntimeWiring(this.wiringConfigurerFactory.apply(this.executors, this.reactiveExecutors));
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> List<T> toList(ObjectProvider<T> provider) {
|
||||
return (provider != null) ? provider.orderedStream().collect(Collectors.toList()) : Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
|
@ -16,9 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.graphql.data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import graphql.GraphQL;
|
||||
|
||||
|
@ -31,6 +29,7 @@ import org.springframework.boot.autoconfigure.graphql.GraphQlAutoConfiguration;
|
|||
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.repository.query.QueryByExampleExecutor;
|
||||
import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;
|
||||
import org.springframework.graphql.data.query.QueryByExampleDataFetcher;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
|
@ -53,15 +52,9 @@ public class GraphQlReactiveQueryByExampleAutoConfiguration {
|
|||
|
||||
@Bean
|
||||
public GraphQlSourceBuilderCustomizer reactiveQueryByExampleRegistrar(
|
||||
ObjectProvider<ReactiveQueryByExampleExecutor<?>> executorsProvider) {
|
||||
|
||||
return (builder) -> {
|
||||
List<ReactiveQueryByExampleExecutor<?>> executors = executorsProvider.stream().collect(Collectors.toList());
|
||||
if (!executors.isEmpty()) {
|
||||
builder.configureRuntimeWiring(
|
||||
QueryByExampleDataFetcher.autoRegistrationConfigurer(Collections.emptyList(), executors));
|
||||
}
|
||||
};
|
||||
ObjectProvider<ReactiveQueryByExampleExecutor<?>> reactiveExecutors) {
|
||||
return new GraphQlQuerydslSourceBuilderCustomizer<>(QueryByExampleDataFetcher::autoRegistrationConfigurer,
|
||||
(ObjectProvider<QueryByExampleExecutor<?>>) null, reactiveExecutors);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.graphql.data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import graphql.GraphQL;
|
||||
|
||||
|
@ -31,6 +29,7 @@ import org.springframework.boot.autoconfigure.graphql.GraphQlAutoConfiguration;
|
|||
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor;
|
||||
import org.springframework.graphql.data.query.QuerydslDataFetcher;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
|
@ -54,16 +53,9 @@ public class GraphQlReactiveQuerydslAutoConfiguration {
|
|||
|
||||
@Bean
|
||||
public GraphQlSourceBuilderCustomizer reactiveQuerydslRegistrar(
|
||||
ObjectProvider<ReactiveQuerydslPredicateExecutor<?>> executorsProvider) {
|
||||
|
||||
return (builder) -> {
|
||||
List<ReactiveQuerydslPredicateExecutor<?>> executors = executorsProvider.stream()
|
||||
.collect(Collectors.toList());
|
||||
if (!executors.isEmpty()) {
|
||||
builder.configureRuntimeWiring(
|
||||
QuerydslDataFetcher.autoRegistrationConfigurer(Collections.emptyList(), executors));
|
||||
}
|
||||
};
|
||||
ObjectProvider<ReactiveQuerydslPredicateExecutor<?>> reactiveExecutors) {
|
||||
return new GraphQlQuerydslSourceBuilderCustomizer<>(QuerydslDataFetcher::autoRegistrationConfigurer,
|
||||
(ObjectProvider<QuerydslPredicateExecutor<?>>) null, reactiveExecutors);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.stream.Collectors;
|
|||
import graphql.GraphQL;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
|
@ -38,6 +39,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
|
@ -46,6 +48,7 @@ import org.springframework.graphql.web.webflux.GraphQlHttpHandler;
|
|||
import org.springframework.graphql.web.webflux.GraphQlWebSocketHandler;
|
||||
import org.springframework.graphql.web.webflux.GraphiQlHandler;
|
||||
import org.springframework.graphql.web.webflux.SchemaHandler;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
|
@ -54,8 +57,10 @@ import org.springframework.web.cors.CorsConfiguration;
|
|||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.config.CorsRegistry;
|
||||
import org.springframework.web.reactive.config.WebFluxConfigurer;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.reactive.socket.server.support.WebSocketUpgradeHandlerPredicate;
|
||||
|
@ -78,6 +83,9 @@ import static org.springframework.web.reactive.function.server.RequestPredicates
|
|||
@EnableConfigurationProperties(GraphQlCorsProperties.class)
|
||||
public class GraphQlWebFluxAutoConfiguration {
|
||||
|
||||
private static final RequestPredicate ACCEPT_JSON_CONTENT = accept(MediaType.APPLICATION_JSON)
|
||||
.and(contentType(MediaType.APPLICATION_JSON));
|
||||
|
||||
private static final Log logger = LogFactory.getLog(GraphQlWebFluxAutoConfiguration.class);
|
||||
|
||||
@Bean
|
||||
|
@ -95,34 +103,32 @@ public class GraphQlWebFluxAutoConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> graphQlEndpoint(GraphQlHttpHandler handler, GraphQlSource graphQlSource,
|
||||
public RouterFunction<ServerResponse> graphQlEndpoint(GraphQlHttpHandler httpHandler, GraphQlSource graphQlSource,
|
||||
GraphQlProperties properties, ResourceLoader resourceLoader) {
|
||||
|
||||
String graphQLPath = properties.getPath();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("GraphQL endpoint HTTP POST " + graphQLPath);
|
||||
}
|
||||
|
||||
RouterFunctions.Builder builder = RouterFunctions.route()
|
||||
.GET(graphQLPath,
|
||||
(request) -> ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED)
|
||||
.headers((headers) -> headers.setAllow(Collections.singleton(HttpMethod.POST))).build())
|
||||
.POST(graphQLPath, accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)),
|
||||
handler::handleRequest);
|
||||
|
||||
String path = properties.getPath();
|
||||
logger.info(LogMessage.format("GraphQL endpoint HTTP POST %s", path));
|
||||
RouterFunctions.Builder builder = RouterFunctions.route();
|
||||
builder = builder.GET(path, this::onlyAllowPost);
|
||||
builder = builder.POST(path, ACCEPT_JSON_CONTENT, httpHandler::handleRequest);
|
||||
if (properties.getGraphiql().isEnabled()) {
|
||||
GraphiQlHandler graphiQlHandler = new GraphiQlHandler(graphQLPath, properties.getWebsocket().getPath());
|
||||
builder = builder.GET(properties.getGraphiql().getPath(), graphiQlHandler::handleRequest);
|
||||
GraphiQlHandler graphQlHandler = new GraphiQlHandler(path, properties.getWebsocket().getPath());
|
||||
builder = builder.GET(properties.getGraphiql().getPath(), graphQlHandler::handleRequest);
|
||||
}
|
||||
|
||||
if (properties.getSchema().getPrinter().isEnabled()) {
|
||||
SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
|
||||
builder = builder.GET(graphQLPath + "/schema", schemaHandler::handleRequest);
|
||||
builder = builder.GET(path + "/schema", schemaHandler::handleRequest);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Mono<ServerResponse> onlyAllowPost(ServerRequest request) {
|
||||
return ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED).headers(this::onlyAllowPost).build();
|
||||
}
|
||||
|
||||
private void onlyAllowPost(HttpHeaders headers) {
|
||||
headers.setAllow(Collections.singleton(HttpMethod.POST));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public static class GraphQlEndpointCorsConfiguration implements WebFluxConfigurer {
|
||||
|
||||
|
@ -161,9 +167,7 @@ public class GraphQlWebFluxAutoConfiguration {
|
|||
public HandlerMapping graphQlWebSocketEndpoint(GraphQlWebSocketHandler graphQlWebSocketHandler,
|
||||
GraphQlProperties properties) {
|
||||
String path = properties.getWebsocket().getPath();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("GraphQL endpoint WebSocket " + path);
|
||||
}
|
||||
logger.info(LogMessage.format("GraphQL endpoint WebSocket %s", path));
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setHandlerPredicate(new WebSocketUpgradeHandlerPredicate());
|
||||
mapping.setUrlMap(Collections.singletonMap(path, graphQlWebSocketHandler));
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.execution.ThreadLocalAccessor;
|
||||
|
@ -51,10 +52,12 @@ import org.springframework.graphql.web.webmvc.GraphQlHttpHandler;
|
|||
import org.springframework.graphql.web.webmvc.GraphQlWebSocketHandler;
|
||||
import org.springframework.graphql.web.webmvc.GraphiQlHandler;
|
||||
import org.springframework.graphql.web.webmvc.SchemaHandler;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
|
@ -62,6 +65,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|||
import org.springframework.web.servlet.function.RequestPredicates;
|
||||
import org.springframework.web.servlet.function.RouterFunction;
|
||||
import org.springframework.web.servlet.function.RouterFunctions;
|
||||
import org.springframework.web.servlet.function.ServerRequest;
|
||||
import org.springframework.web.servlet.function.ServerResponse;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
|
||||
|
@ -102,34 +106,33 @@ public class GraphQlWebMvcAutoConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler handler, GraphQlSource graphQlSource,
|
||||
GraphQlProperties properties, ResourceLoader resourceLoader) {
|
||||
|
||||
String graphQLPath = properties.getPath();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("GraphQL endpoint HTTP POST " + graphQLPath);
|
||||
}
|
||||
|
||||
RouterFunctions.Builder builder = RouterFunctions.route()
|
||||
.GET(graphQLPath,
|
||||
(request) -> ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED)
|
||||
.headers((headers) -> headers.setAllow(Collections.singleton(HttpMethod.POST))).build())
|
||||
.POST(graphQLPath, RequestPredicates.contentType(MediaType.APPLICATION_JSON)
|
||||
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::handleRequest);
|
||||
|
||||
public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler httpHandler,
|
||||
GraphQlSource graphQlSource, GraphQlProperties properties, ResourceLoader resourceLoader) {
|
||||
String path = properties.getPath();
|
||||
logger.info(LogMessage.format("GraphQL endpoint HTTP POST %s", path));
|
||||
RouterFunctions.Builder builder = RouterFunctions.route();
|
||||
builder = builder.GET(path, this::onlyAllowPost);
|
||||
builder = builder.POST(path, RequestPredicates.contentType(MediaType.APPLICATION_JSON)
|
||||
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), httpHandler::handleRequest);
|
||||
if (properties.getGraphiql().isEnabled()) {
|
||||
GraphiQlHandler graphiQLHandler = new GraphiQlHandler(graphQLPath, properties.getWebsocket().getPath());
|
||||
GraphiQlHandler graphiQLHandler = new GraphiQlHandler(path, properties.getWebsocket().getPath());
|
||||
builder = builder.GET(properties.getGraphiql().getPath(), graphiQLHandler::handleRequest);
|
||||
}
|
||||
|
||||
if (properties.getSchema().getPrinter().isEnabled()) {
|
||||
SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
|
||||
builder = builder.GET(graphQLPath + "/schema", schemaHandler::handleRequest);
|
||||
builder = builder.GET(path + "/schema", schemaHandler::handleRequest);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private ServerResponse onlyAllowPost(ServerRequest request) {
|
||||
return ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED).headers(this::onlyAllowPost).build();
|
||||
}
|
||||
|
||||
private void onlyAllowPost(HttpHeaders headers) {
|
||||
headers.setAllow(Collections.singleton(HttpMethod.POST));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public static class GraphQlEndpointCorsConfiguration implements WebMvcConfigurer {
|
||||
|
||||
|
@ -161,25 +164,29 @@ public class GraphQlWebMvcAutoConfiguration {
|
|||
@ConditionalOnMissingBean
|
||||
public GraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler,
|
||||
GraphQlProperties properties, HttpMessageConverters converters) {
|
||||
|
||||
return new GraphQlWebSocketHandler(webGraphQlHandler, getJsonConverter(converters),
|
||||
properties.getWebsocket().getConnectionInitTimeout());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static GenericHttpMessageConverter<Object> getJsonConverter(HttpMessageConverters converters) {
|
||||
return converters.getConverters().stream()
|
||||
.filter((candidate) -> candidate.canRead(Map.class, MediaType.APPLICATION_JSON)).findFirst()
|
||||
.map((converter) -> (GenericHttpMessageConverter<Object>) converter)
|
||||
private GenericHttpMessageConverter<Object> getJsonConverter(HttpMessageConverters converters) {
|
||||
return converters.getConverters().stream().filter(this::canReadJsonMap).findFirst()
|
||||
.map(this::asGenericHttpMessageConverter)
|
||||
.orElseThrow(() -> new IllegalStateException("No JSON converter"));
|
||||
}
|
||||
|
||||
private boolean canReadJsonMap(HttpMessageConverter<?> candidate) {
|
||||
return candidate.canRead(Map.class, MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private GenericHttpMessageConverter<Object> asGenericHttpMessageConverter(HttpMessageConverter<?> converter) {
|
||||
return (GenericHttpMessageConverter<Object>) converter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HandlerMapping graphQlWebSocketMapping(GraphQlWebSocketHandler handler, GraphQlProperties properties) {
|
||||
String path = properties.getWebsocket().getPath();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("GraphQL endpoint WebSocket " + path);
|
||||
}
|
||||
logger.info(LogMessage.format("GraphQL endpoint WebSocket %s", path));
|
||||
WebSocketHandlerMapping mapping = new WebSocketHandlerMapping();
|
||||
mapping.setWebSocketUpgradeMatch(true);
|
||||
mapping.setUrlMap(Collections.singletonMap(path,
|
||||
|
|
Loading…
Reference in New Issue