Allow configuring schema through GraphQlSource customizer
As of gh-117, the GraphQlAutoConfiguration throws an exception if no schema file was found while scanning configured locations. This prevents developers from manually configuring the schema using `GraphQlSourceBuilderCustomizer` instances. This commit ensures that a `MissingSchemaException` is only raised if no schema was configured at the time we're building the actual GraphQlSource. This exception is later wrapped by the GraphQlAutoConfiguration to raise an `InvalidSchemaLocationsException` with useful information about configured schema locations. Fixes gh-124
This commit is contained in:
@@ -38,6 +38,7 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.graphql.execution.DataFetcherExceptionResolver;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.execution.MissingSchemaException;
|
||||
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
|
||||
|
||||
/**
|
||||
@@ -71,7 +72,12 @@ public class GraphQlAutoConfiguration {
|
||||
.instrumentation(instrumentationsProvider.orderedStream().collect(Collectors.toList()));
|
||||
wiringConfigurers.orderedStream().forEach(builder::configureRuntimeWiring);
|
||||
sourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder.build();
|
||||
try {
|
||||
return builder.build();
|
||||
}
|
||||
catch (MissingSchemaException exc) {
|
||||
throw new InvalidSchemaLocationsException(properties.getSchema().getLocations(), resourcePatternResolver, exc);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Resource> resolveSchemaResources(ResourcePatternResolver resolver, List<String> schemaLocations) throws IOException {
|
||||
@@ -86,9 +92,6 @@ public class GraphQlAutoConfiguration {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (schemaResources.isEmpty()) {
|
||||
throw new MissingSchemaException(schemaLocations, resolver);
|
||||
}
|
||||
return schemaResources;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,18 +21,25 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
|
||||
/**
|
||||
* {@link MissingSchemaException} thrown when no schema can be found in the provided locations.
|
||||
* {@link InvalidSchemaLocationsException} thrown when no schema file could be found in the provided locations.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class MissingSchemaException extends RuntimeException {
|
||||
public class InvalidSchemaLocationsException extends NestedRuntimeException {
|
||||
|
||||
private final List<SchemaLocation> schemaLocations;
|
||||
|
||||
public MissingSchemaException(List<String> locations, ResourcePatternResolver resolver) {
|
||||
public InvalidSchemaLocationsException(List<String> locations, ResourcePatternResolver resolver) {
|
||||
this(locations, resolver, null);
|
||||
}
|
||||
|
||||
public InvalidSchemaLocationsException(List<String> locations, ResourcePatternResolver resolver, Throwable cause) {
|
||||
super("No schema file could be found in the provided locations.", cause);
|
||||
List<SchemaLocation> providedLocations = new ArrayList<>();
|
||||
for (String location : locations) {
|
||||
try {
|
||||
@@ -21,17 +21,17 @@ import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
|
||||
/**
|
||||
* An implementation of {@link AbstractFailureAnalyzer} to analyze failures caused by
|
||||
* {@link MissingSchemaException}.
|
||||
* {@link InvalidSchemaLocationsException}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class MissingSchemaExceptionFailureAnalyzer extends AbstractFailureAnalyzer<MissingSchemaException> {
|
||||
class InvalidSchemaLocationsExceptionFailureAnalyzer extends AbstractFailureAnalyzer<InvalidSchemaLocationsException> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, MissingSchemaException cause) {
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, InvalidSchemaLocationsException cause) {
|
||||
String message = "Could not find any GraphQL schema file under configured locations.";
|
||||
StringBuilder action = new StringBuilder("Check that the following locations contain schema files: " + System.lineSeparator());
|
||||
for (MissingSchemaException.SchemaLocation schemaLocation : cause.getSchemaLocations()) {
|
||||
for (InvalidSchemaLocationsException.SchemaLocation schemaLocation : cause.getSchemaLocations()) {
|
||||
action.append(String.format("- '%s' (%s)" + System.lineSeparator(), schemaLocation.getUri(), schemaLocation.getLocation()));
|
||||
}
|
||||
return new FailureAnalysis(message, action.toString(), cause);
|
||||
@@ -11,7 +11,7 @@ org.springframework.graphql.boot.data.GraphQlWebFluxQuerydslAutoConfiguration
|
||||
|
||||
# Failure Analyzers
|
||||
org.springframework.boot.diagnostics.FailureAnalyzer=\
|
||||
org.springframework.graphql.boot.MissingSchemaExceptionFailureAnalyzer
|
||||
org.springframework.graphql.boot.InvalidSchemaLocationsExceptionFailureAnalyzer
|
||||
|
||||
# Spring Test @AutoConfigureGraphQlTester
|
||||
org.springframework.graphql.boot.test.tester.AutoConfigureGraphQlTester=\
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.execution.MissingSchemaException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ class DefaultGraphQlSourceBuilder implements GraphQlSource.Builder {
|
||||
public GraphQlSource build() {
|
||||
TypeDefinitionRegistry registry = this.schemaResources.stream()
|
||||
.map(this::parseSchemaResource).reduce(TypeDefinitionRegistry::merge)
|
||||
.orElseThrow(() -> new IllegalArgumentException("'schemaResources' should not be empty"));
|
||||
.orElseThrow(MissingSchemaException::new);
|
||||
|
||||
RuntimeWiring.Builder runtimeWiringBuilder = RuntimeWiring.newRuntimeWiring();
|
||||
this.runtimeWiringConfigurers.forEach(configurer -> configurer.configure(runtimeWiringBuilder));
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2020-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.execution;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Indicates that no GraphQL schema definition was configured on the {@link GraphQlSource.Builder}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class MissingSchemaException extends NestedRuntimeException {
|
||||
|
||||
public MissingSchemaException() {
|
||||
super("No GraphQL schema definition was configured.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user