Skip to content

Commit ff9a421

Browse files
committed
Auto-configure schema printer endpoint
This commit configuresa new endpoint for printing in text format the resolved GraphQL schema. This endpoint is exposed by default under "/graphql/schema" and must be enabled with "spring.graphql.schema.printer=true". See gh-29140
1 parent b38d045 commit ff9a421

File tree

5 files changed

+57
-4
lines changed

5 files changed

+57
-4
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/GraphQlProperties.java

+24
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public static class Schema {
6060
*/
6161
private String[] fileExtensions = new String[] { ".graphqls", ".gqls" };
6262

63+
private final Printer printer = new Printer();
64+
6365
public String[] getLocations() {
6466
return this.locations;
6567
}
@@ -81,6 +83,28 @@ private String[] appendSlashIfNecessary(String[] locations) {
8183
.toArray(String[]::new);
8284
}
8385

86+
public Printer getPrinter() {
87+
return this.printer;
88+
}
89+
90+
public static class Printer {
91+
92+
/**
93+
* Whether the endpoint that prints the schema is enabled. Schema is available
94+
* under spring.graphql.path + "/schema".
95+
*/
96+
private boolean enabled = false;
97+
98+
public boolean isEnabled() {
99+
return this.enabled;
100+
}
101+
102+
public void setEnabled(boolean enabled) {
103+
this.enabled = enabled;
104+
}
105+
106+
}
107+
84108
}
85109

86110
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfiguration.java

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.springframework.graphql.web.WebGraphQlHandler;
4141
import org.springframework.graphql.web.WebInterceptor;
4242
import org.springframework.graphql.web.webflux.GraphQlHttpHandler;
43+
import org.springframework.graphql.web.webflux.SchemaHandler;
4344
import org.springframework.http.HttpMethod;
4445
import org.springframework.http.HttpStatus;
4546
import org.springframework.http.MediaType;
@@ -96,6 +97,11 @@ public RouterFunction<ServerResponse> graphQlEndpoint(GraphQlHttpHandler handler
9697
.POST(graphQLPath, accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)),
9798
handler::handleRequest);
9899

100+
if (properties.getSchema().getPrinter().isEnabled()) {
101+
SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
102+
builder = builder.GET(graphQLPath + "/schema", schemaHandler::handleRequest);
103+
}
104+
99105
return builder.build();
100106
}
101107

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java

+6
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.springframework.graphql.web.WebGraphQlHandler;
4242
import org.springframework.graphql.web.WebInterceptor;
4343
import org.springframework.graphql.web.webmvc.GraphQlHttpHandler;
44+
import org.springframework.graphql.web.webmvc.SchemaHandler;
4445
import org.springframework.http.HttpMethod;
4546
import org.springframework.http.HttpStatus;
4647
import org.springframework.http.MediaType;
@@ -97,6 +98,11 @@ public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler h
9798
.POST(graphQLPath, RequestPredicates.contentType(MediaType.APPLICATION_JSON)
9899
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::handleRequest);
99100

101+
if (properties.getSchema().getPrinter().isEnabled()) {
102+
SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
103+
builder = builder.GET(graphQLPath + "/schema", schemaHandler::handleRequest);
104+
}
105+
100106
return builder.build();
101107
}
102108

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfigurationTests.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import org.springframework.http.MediaType;
3939
import org.springframework.test.web.reactive.server.WebTestClient;
4040

41+
import static org.hamcrest.Matchers.containsString;
42+
4143
/**
4244
* Tests for {@link GraphQlWebFluxAutoConfiguration}
4345
*
@@ -51,8 +53,8 @@ class GraphQlWebFluxAutoConfigurationTests {
5153
.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,
5254
CodecsAutoConfiguration.class, JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
5355
GraphQlWebFluxAutoConfiguration.class))
54-
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
55-
.withPropertyValues("spring.main.web-application-type=reactive");
56+
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class).withPropertyValues(
57+
"spring.main.web-application-type=reactive", "spring.graphql.schema.printer.enabled=true");
5658

5759
@Test
5860
void simpleQueryShouldWork() {
@@ -92,6 +94,13 @@ void shouldConfigureWebInterceptors() {
9294
});
9395
}
9496

97+
@Test
98+
void shouldExposeSchemaEndpoint() {
99+
testWithWebClient((client) -> client.get().uri("/schema").accept(MediaType.ALL).exchange()
100+
.expectStatus().isOk().expectHeader().contentType(MediaType.TEXT_PLAIN).expectBody(String.class)
101+
.value(containsString("type Book")));
102+
}
103+
95104
private void testWithWebClient(Consumer<WebTestClient> consumer) {
96105
this.contextRunner.run((context) -> {
97106
WebTestClient client = WebTestClient.bindToApplicationContext(context).configureClient()

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.graphql.servlet;
1818

1919
import graphql.schema.idl.TypeRuntimeWiring;
20+
import org.hamcrest.Matchers;
2021
import org.junit.jupiter.api.Test;
2122

2223
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -56,8 +57,8 @@ class GraphQlWebMvcAutoConfigurationTests {
5657
AutoConfigurations.of(DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
5758
HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class,
5859
GraphQlAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class))
59-
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
60-
.withPropertyValues("spring.main.web-application-type=servlet");
60+
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class).withPropertyValues(
61+
"spring.main.web-application-type=servlet", "spring.graphql.schema.printer.enabled=true");
6162

6263
@Test
6364
void simpleQueryShouldWork() {
@@ -99,6 +100,13 @@ void shouldConfigureWebInterceptors() {
99100
});
100101
}
101102

103+
@Test
104+
void shouldExposeSchemaEndpoint() {
105+
testWith((mockMvc) -> mockMvc.perform(get("/graphql/schema")).andExpect(status().isOk())
106+
.andExpect(content().contentType(MediaType.TEXT_PLAIN))
107+
.andExpect(content().string(Matchers.containsString("type Book"))));
108+
}
109+
102110
private void testWith(MockMvcConsumer mockMvcConsumer) {
103111
this.contextRunner.run((context) -> {
104112
MediaType mediaType = MediaType.APPLICATION_JSON;

0 commit comments

Comments
 (0)