Skip to content

Commit 08ac776

Browse files
committed
Add ConnectionTypeConfigurer
See gh-620
1 parent e0bb96b commit 08ac776

File tree

8 files changed

+69
-53
lines changed

8 files changed

+69
-53
lines changed

spring-graphql/src/main/java/org/springframework/graphql/execution/ConnectionTypeGenerator.java renamed to spring-graphql/src/main/java/org/springframework/graphql/execution/ConnectionTypeDefinitionConfigurer.java

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import java.util.LinkedHashSet;
1919
import java.util.Set;
20-
import java.util.function.Function;
2120
import java.util.stream.Collectors;
2221

2322
import graphql.language.FieldDefinition;
@@ -30,18 +29,20 @@
3029
import graphql.schema.idl.TypeDefinitionRegistry;
3130

3231
/**
33-
* Exposes the {@link #generateConnectionTypes(TypeDefinitionRegistry)
34-
* generateConnectionTypes method} for adding boilerplate type definitions to a
35-
* {@link TypeDefinitionRegistry}, for pagination based on the Relay
36-
* <a href="https://relay.dev/graphql/connections.htm">GraphQL Cursor Connections Specification</a>.
32+
* {@link TypeDefinitionConfigurer} that generates "Connection" types by looking
33+
* for fields whose type definition name ends in "Connection", considered by the
34+
* <a href="https://relay.dev/graphql/connections.htm">GraphQL Cursor Connections Specification</a>
35+
* to be a {@literal Connection Type}, and adding the required type definitions
36+
* if they don't already exist.
3737
*
38-
* <p>Use {@link GraphQlSource.SchemaResourceBuilder#configureTypeDefinitionRegistry(Function)}
39-
* to enable connection type generation.
38+
* <p>This is intended to be set on
39+
* {@link GraphQlSource.SchemaResourceBuilder#configureTypeDefinitions(TypeDefinitionConfigurer)
40+
* GraphQlSource.Builder}.
4041
*
4142
* @author Rossen Stoyanchev
4243
* @since 1.2
4344
*/
44-
public class ConnectionTypeGenerator {
45+
public class ConnectionTypeDefinitionConfigurer implements TypeDefinitionConfigurer {
4546

4647
private static final TypeName STRING_TYPE = new TypeName("String");
4748

@@ -50,14 +51,8 @@ public class ConnectionTypeGenerator {
5051
private static final TypeName PAGE_INFO_TYPE = new TypeName("PageInfo");
5152

5253

53-
/**
54-
* Find fields whose type definition name ends in "Connection", considered
55-
* by the spec to be a {@literal Connection Type}, and add type definitions
56-
* for all such types, if they don't exist already.
57-
* @param registry the registry to check and add types to
58-
* @return the same registry instance with additional types added
59-
*/
60-
public TypeDefinitionRegistry generateConnectionTypes(TypeDefinitionRegistry registry) {
54+
@Override
55+
public void configure(TypeDefinitionRegistry registry) {
6156

6257
Set<String> typeNames = findConnectionTypeNames(registry);
6358

@@ -89,8 +84,6 @@ public TypeDefinitionRegistry generateConnectionTypes(TypeDefinitionRegistry reg
8984
.build());
9085
});
9186
}
92-
93-
return registry;
9487
}
9588

9689
private static Set<String> findConnectionTypeNames(TypeDefinitionRegistry registry) {

spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultSchemaResourceGraphQlSourceBuilder.java

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import java.util.List;
2525
import java.util.Set;
2626
import java.util.function.BiFunction;
27-
import java.util.function.Function;
2827
import java.util.stream.Collectors;
2928

3029
import graphql.language.InterfaceTypeDefinition;
@@ -61,8 +60,7 @@ final class DefaultSchemaResourceGraphQlSourceBuilder
6160

6261
private final Set<Resource> schemaResources = new LinkedHashSet<>();
6362

64-
@Nullable
65-
private Function<TypeDefinitionRegistry, TypeDefinitionRegistry> typeDefinitionRegistryConfigurer;
63+
private List<TypeDefinitionConfigurer> typeDefinitionConfigurers = new ArrayList<>();
6664

6765
private final List<RuntimeWiringConfigurer> runtimeWiringConfigurers = new ArrayList<>();
6866

@@ -81,12 +79,8 @@ public DefaultSchemaResourceGraphQlSourceBuilder schemaResources(Resource... res
8179
}
8280

8381
@Override
84-
public GraphQlSource.SchemaResourceBuilder configureTypeDefinitionRegistry(
85-
Function<TypeDefinitionRegistry, TypeDefinitionRegistry> configurer) {
86-
87-
this.typeDefinitionRegistryConfigurer = (this.typeDefinitionRegistryConfigurer != null ?
88-
this.typeDefinitionRegistryConfigurer.andThen(configurer) : configurer);
89-
82+
public GraphQlSource.SchemaResourceBuilder configureTypeDefinitions(TypeDefinitionConfigurer configurer) {
83+
this.typeDefinitionConfigurers.add(configurer);
9084
return this;
9185
}
9286

@@ -118,8 +112,8 @@ protected GraphQLSchema initGraphQlSchema() {
118112
.reduce(TypeDefinitionRegistry::merge)
119113
.orElseThrow(MissingSchemaException::new);
120114

121-
if (this.typeDefinitionRegistryConfigurer != null) {
122-
registry = this.typeDefinitionRegistryConfigurer.apply(registry);
115+
for (TypeDefinitionConfigurer configurer : this.typeDefinitionConfigurers) {
116+
configurer.configure(registry);
123117
}
124118

125119
logger.info("Loaded " + this.schemaResources.size() + " resource(s) in the GraphQL schema.");

spring-graphql/src/main/java/org/springframework/graphql/execution/GraphQlSource.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,14 @@ interface SchemaResourceBuilder extends Builder<SchemaResourceBuilder> {
173173
SchemaResourceBuilder schemaResources(Resource... resources);
174174

175175
/**
176-
* Provide a function to customize the {@link TypeDefinitionRegistry}
177-
* created by parsing schema files. This allows adding or changing schema
178-
* type definitions before {@link GraphQLSchema} is created and validated.
179-
* @param configurer the function to apply accepting the current
180-
* {@link TypeDefinitionRegistry} and returning the one to use, likely
181-
* the same instance since {@link TypeDefinitionRegistry} is mutable.
176+
* Customize the {@link TypeDefinitionRegistry} created from parsed
177+
* schema files, adding or changing schema type definitions before the
178+
* {@link GraphQLSchema} is created and validated.
179+
* @param configurer the configurer to apply
182180
* @return the current builder
183-
* @sine 1.2
181+
* @since 1.2
184182
*/
185-
SchemaResourceBuilder configureTypeDefinitionRegistry(
186-
Function<TypeDefinitionRegistry, TypeDefinitionRegistry> configurer);
183+
SchemaResourceBuilder configureTypeDefinitions(TypeDefinitionConfigurer configurer);
187184

188185
/**
189186
* Configure the underlying {@link RuntimeWiring.Builder} to register
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.graphql.execution;
17+
18+
import graphql.schema.GraphQLSchema;
19+
import graphql.schema.idl.TypeDefinitionRegistry;
20+
21+
/**
22+
* Callback that allows customizing the {@link TypeDefinitionRegistry} created
23+
* from parsed schema files. It allows adding schema types programmatically
24+
* before the registry is used to create {@link GraphQLSchema}.
25+
*
26+
* @author Rossen Stoyanchev
27+
* @since 1.2
28+
*/
29+
public interface TypeDefinitionConfigurer {
30+
31+
/**
32+
* Customize the given {@link TypeDefinitionRegistry}.
33+
* @param registry the registry to customize
34+
*/
35+
void configure(TypeDefinitionRegistry registry);
36+
37+
}

spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPaginationTests.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import org.springframework.graphql.data.query.ScrollPositionCursorStrategy;
3636
import org.springframework.graphql.data.query.ScrollSubrange;
3737
import org.springframework.graphql.data.query.WindowConnectionAdapter;
38-
import org.springframework.graphql.execution.ConnectionTypeGenerator;
38+
import org.springframework.graphql.execution.ConnectionTypeDefinitionConfigurer;
3939
import org.springframework.stereotype.Controller;
4040

4141
import static org.assertj.core.api.Assertions.assertThat;
@@ -83,8 +83,7 @@ void forwardPagination() throws Exception {
8383

8484
ExecutionGraphQlService graphQlService = graphQlService((configurer, setup) -> {
8585

86-
ConnectionTypeGenerator typeGenerator = new ConnectionTypeGenerator();
87-
setup.typeDefinitionRegistryConfigurer(typeGenerator::generateConnectionTypes);
86+
setup.typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer());
8887

8988
ScrollPositionCursorStrategy cursorStrategy = new ScrollPositionCursorStrategy();
9089
WindowConnectionAdapter connectionAdapter = new WindowConnectionAdapter(cursorStrategy);

spring-graphql/src/test/java/org/springframework/graphql/data/pagination/ConnectionFieldTypeVisitorTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import org.springframework.graphql.ExecutionGraphQlResponse;
2727
import org.springframework.graphql.GraphQlSetup;
2828
import org.springframework.graphql.TestExecutionRequest;
29-
import org.springframework.graphql.execution.ConnectionTypeGenerator;
29+
import org.springframework.graphql.execution.ConnectionTypeDefinitionConfigurer;
3030

3131
import static org.assertj.core.api.Assertions.assertThat;
3232

@@ -75,7 +75,7 @@ void dataFetcherDecoration() throws Exception {
7575

7676
ExecutionGraphQlResponse response = GraphQlSetup.schemaContent(schemaContent)
7777
.dataFetcher("Query", "books", env -> BookSource.books())
78-
.typeDefinitionRegistryConfigurer(new ConnectionTypeGenerator()::generateConnectionTypes)
78+
.typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer())
7979
.typeVisitor(ConnectionFieldTypeVisitor.create(List.of(adapter)))
8080
.toGraphQlService()
8181
.execute(TestExecutionRequest.forDocument(document))

spring-graphql/src/test/java/org/springframework/graphql/execution/ConnectionTypeGeneratorTests.java renamed to spring-graphql/src/test/java/org/springframework/graphql/execution/ConnectionTypeDefinitionConfigurerTests.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@
3838
import static org.assertj.core.api.Assertions.assertThat;
3939

4040
/**
41-
* Unit tests for {@link ConnectionTypeGenerator}.
41+
* Unit tests for {@link ConnectionTypeDefinitionConfigurer}.
4242
*
4343
* @author Rossen Stoyanchev
4444
* @since 1.2
4545
*/
46-
public class ConnectionTypeGeneratorTests {
46+
public class ConnectionTypeDefinitionConfigurerTests {
4747

4848
@Test
4949
void connectionTypeGeneration() throws Exception {
@@ -108,8 +108,7 @@ void connectionTypeGeneration() throws Exception {
108108
}
109109

110110
private GraphQlSetup initGraphQlSetup(String schema) {
111-
ConnectionTypeGenerator generator = new ConnectionTypeGenerator();
112-
return GraphQlSetup.schemaContent(schema).typeDefinitionRegistryConfigurer(generator::generateConnectionTypes);
111+
return GraphQlSetup.schemaContent(schema).typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer());
113112
}
114113

115114
private static <N> Connection<N> createConnection(

spring-graphql/src/testFixtures/java/org/springframework/graphql/GraphQlSetup.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@
1919
import java.util.ArrayList;
2020
import java.util.Arrays;
2121
import java.util.List;
22-
import java.util.function.Function;
2322

2423
import graphql.GraphQL;
2524
import graphql.execution.instrumentation.Instrumentation;
2625
import graphql.schema.DataFetcher;
2726
import graphql.schema.GraphQLTypeVisitor;
2827
import graphql.schema.TypeResolver;
29-
import graphql.schema.idl.TypeDefinitionRegistry;
3028

3129
import org.springframework.context.ApplicationContext;
3230
import org.springframework.core.io.ByteArrayResource;
@@ -38,6 +36,7 @@
3836
import org.springframework.graphql.execution.GraphQlSource;
3937
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
4038
import org.springframework.graphql.execution.SubscriptionExceptionResolver;
39+
import org.springframework.graphql.execution.TypeDefinitionConfigurer;
4140
import org.springframework.graphql.server.WebGraphQlHandler;
4241
import org.springframework.graphql.server.WebGraphQlInterceptor;
4342
import org.springframework.graphql.server.WebGraphQlSetup;
@@ -82,10 +81,8 @@ public GraphQlSetup dataFetcher(String type, String field, DataFetcher<?> dataFe
8281
wiringBuilder.type(type, typeBuilder -> typeBuilder.dataFetcher(field, dataFetcher)));
8382
}
8483

85-
public GraphQlSetup typeDefinitionRegistryConfigurer(
86-
Function<TypeDefinitionRegistry, TypeDefinitionRegistry> configurer) {
87-
88-
this.graphQlSourceBuilder.configureTypeDefinitionRegistry(configurer);
84+
public GraphQlSetup typeDefinitionConfigurer(TypeDefinitionConfigurer configurer) {
85+
this.graphQlSourceBuilder.configureTypeDefinitions(configurer);
8986
return this;
9087
}
9188

0 commit comments

Comments
 (0)