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
This commit is contained in:
parent
b38d04556e
commit
ff9a421786
|
@ -60,6 +60,8 @@ public class GraphQlProperties {
|
||||||
*/
|
*/
|
||||||
private String[] fileExtensions = new String[] { ".graphqls", ".gqls" };
|
private String[] fileExtensions = new String[] { ".graphqls", ".gqls" };
|
||||||
|
|
||||||
|
private final Printer printer = new Printer();
|
||||||
|
|
||||||
public String[] getLocations() {
|
public String[] getLocations() {
|
||||||
return this.locations;
|
return this.locations;
|
||||||
}
|
}
|
||||||
|
@ -81,6 +83,28 @@ public class GraphQlProperties {
|
||||||
.toArray(String[]::new);
|
.toArray(String[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Printer getPrinter() {
|
||||||
|
return this.printer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Printer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the endpoint that prints the schema is enabled. Schema is available
|
||||||
|
* under spring.graphql.path + "/schema".
|
||||||
|
*/
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return this.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ import org.springframework.graphql.execution.GraphQlSource;
|
||||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||||
import org.springframework.graphql.web.WebInterceptor;
|
import org.springframework.graphql.web.WebInterceptor;
|
||||||
import org.springframework.graphql.web.webflux.GraphQlHttpHandler;
|
import org.springframework.graphql.web.webflux.GraphQlHttpHandler;
|
||||||
|
import org.springframework.graphql.web.webflux.SchemaHandler;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
@ -96,6 +97,11 @@ public class GraphQlWebFluxAutoConfiguration {
|
||||||
.POST(graphQLPath, accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)),
|
.POST(graphQLPath, accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)),
|
||||||
handler::handleRequest);
|
handler::handleRequest);
|
||||||
|
|
||||||
|
if (properties.getSchema().getPrinter().isEnabled()) {
|
||||||
|
SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
|
||||||
|
builder = builder.GET(graphQLPath + "/schema", schemaHandler::handleRequest);
|
||||||
|
}
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.springframework.graphql.execution.ThreadLocalAccessor;
|
||||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||||
import org.springframework.graphql.web.WebInterceptor;
|
import org.springframework.graphql.web.WebInterceptor;
|
||||||
import org.springframework.graphql.web.webmvc.GraphQlHttpHandler;
|
import org.springframework.graphql.web.webmvc.GraphQlHttpHandler;
|
||||||
|
import org.springframework.graphql.web.webmvc.SchemaHandler;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
@ -97,6 +98,11 @@ public class GraphQlWebMvcAutoConfiguration {
|
||||||
.POST(graphQLPath, RequestPredicates.contentType(MediaType.APPLICATION_JSON)
|
.POST(graphQLPath, RequestPredicates.contentType(MediaType.APPLICATION_JSON)
|
||||||
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::handleRequest);
|
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::handleRequest);
|
||||||
|
|
||||||
|
if (properties.getSchema().getPrinter().isEnabled()) {
|
||||||
|
SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
|
||||||
|
builder = builder.GET(graphQLPath + "/schema", schemaHandler::handleRequest);
|
||||||
|
}
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link GraphQlWebFluxAutoConfiguration}
|
* Tests for {@link GraphQlWebFluxAutoConfiguration}
|
||||||
*
|
*
|
||||||
|
@ -51,8 +53,8 @@ class GraphQlWebFluxAutoConfigurationTests {
|
||||||
.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,
|
||||||
CodecsAutoConfiguration.class, JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
|
CodecsAutoConfiguration.class, JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
|
||||||
GraphQlWebFluxAutoConfiguration.class))
|
GraphQlWebFluxAutoConfiguration.class))
|
||||||
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
|
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class).withPropertyValues(
|
||||||
.withPropertyValues("spring.main.web-application-type=reactive");
|
"spring.main.web-application-type=reactive", "spring.graphql.schema.printer.enabled=true");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void simpleQueryShouldWork() {
|
void simpleQueryShouldWork() {
|
||||||
|
@ -92,6 +94,13 @@ class GraphQlWebFluxAutoConfigurationTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldExposeSchemaEndpoint() {
|
||||||
|
testWithWebClient((client) -> client.get().uri("/schema").accept(MediaType.ALL).exchange()
|
||||||
|
.expectStatus().isOk().expectHeader().contentType(MediaType.TEXT_PLAIN).expectBody(String.class)
|
||||||
|
.value(containsString("type Book")));
|
||||||
|
}
|
||||||
|
|
||||||
private void testWithWebClient(Consumer<WebTestClient> consumer) {
|
private void testWithWebClient(Consumer<WebTestClient> consumer) {
|
||||||
this.contextRunner.run((context) -> {
|
this.contextRunner.run((context) -> {
|
||||||
WebTestClient client = WebTestClient.bindToApplicationContext(context).configureClient()
|
WebTestClient client = WebTestClient.bindToApplicationContext(context).configureClient()
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.boot.autoconfigure.graphql.servlet;
|
package org.springframework.boot.autoconfigure.graphql.servlet;
|
||||||
|
|
||||||
import graphql.schema.idl.TypeRuntimeWiring;
|
import graphql.schema.idl.TypeRuntimeWiring;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
@ -56,8 +57,8 @@ class GraphQlWebMvcAutoConfigurationTests {
|
||||||
AutoConfigurations.of(DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
AutoConfigurations.of(DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||||
HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class,
|
HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||||
GraphQlAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class))
|
GraphQlAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class))
|
||||||
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
|
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class).withPropertyValues(
|
||||||
.withPropertyValues("spring.main.web-application-type=servlet");
|
"spring.main.web-application-type=servlet", "spring.graphql.schema.printer.enabled=true");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void simpleQueryShouldWork() {
|
void simpleQueryShouldWork() {
|
||||||
|
@ -99,6 +100,13 @@ class GraphQlWebMvcAutoConfigurationTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldExposeSchemaEndpoint() {
|
||||||
|
testWith((mockMvc) -> mockMvc.perform(get("/graphql/schema")).andExpect(status().isOk())
|
||||||
|
.andExpect(content().contentType(MediaType.TEXT_PLAIN))
|
||||||
|
.andExpect(content().string(Matchers.containsString("type Book"))));
|
||||||
|
}
|
||||||
|
|
||||||
private void testWith(MockMvcConsumer mockMvcConsumer) {
|
private void testWith(MockMvcConsumer mockMvcConsumer) {
|
||||||
this.contextRunner.run((context) -> {
|
this.contextRunner.run((context) -> {
|
||||||
MediaType mediaType = MediaType.APPLICATION_JSON;
|
MediaType mediaType = MediaType.APPLICATION_JSON;
|
||||||
|
|
Loading…
Reference in New Issue