Polish GraphQL changes

See gh-29140
Closes gh-29194
pull/29200/head
izeye 3 years ago committed by Brian Clozel
parent 0d616b8924
commit 728206dba0

@ -35,6 +35,12 @@ import io.micrometer.core.instrument.Timer;
import org.springframework.boot.actuate.metrics.AutoTimer;
import org.springframework.lang.Nullable;
/**
* Micrometer-based {@link SimpleInstrumentation}.
*
* @author Brian Clozel
* @since 2.7.0
*/
public class GraphQlMetricsInstrumentation extends SimpleInstrumentation {
private final MeterRegistry registry;
@ -127,7 +133,7 @@ public class GraphQlMetricsInstrumentation extends SimpleInstrumentation {
private Timer.Sample sample;
private AtomicLong dataFetchingCount = new AtomicLong(0L);
private final AtomicLong dataFetchingCount = new AtomicLong();
RequestMetricsInstrumentationState(AutoTimer autoTimer, MeterRegistry registry) {
this.timer = autoTimer.builder("graphql.request");

@ -34,7 +34,7 @@ import org.springframework.util.CollectionUtils;
* Factory methods for Tags associated with a GraphQL request.
*
* @author Brian Clozel
* @since 1.0.0
* @since 2.7.0
*/
public final class GraphQlTags {
@ -72,7 +72,7 @@ public final class GraphQlTags {
builder.append('$');
for (Object segment : pathSegments) {
try {
int index = Integer.parseUnsignedInt(segment.toString());
Integer.parseUnsignedInt(segment.toString());
builder.append("[*]");
}
catch (NumberFormatException exc) {
@ -90,13 +90,13 @@ public final class GraphQlTags {
public static Tag dataFetchingPath(InstrumentationFieldFetchParameters parameters) {
ExecutionStepInfo executionStepInfo = parameters.getExecutionStepInfo();
StringBuilder dataFetchingType = new StringBuilder();
StringBuilder dataFetchingPath = new StringBuilder();
if (executionStepInfo.hasParent() && executionStepInfo.getParent().getType() instanceof GraphQLObjectType) {
dataFetchingType.append(((GraphQLObjectType) executionStepInfo.getParent().getType()).getName());
dataFetchingType.append('.');
dataFetchingPath.append(((GraphQLObjectType) executionStepInfo.getParent().getType()).getName());
dataFetchingPath.append('.');
}
dataFetchingType.append(executionStepInfo.getPath().getSegmentName());
return Tag.of("path", dataFetchingType.toString());
dataFetchingPath.append(executionStepInfo.getPath().getSegmentName());
return Tag.of("path", dataFetchingPath.toString());
}
}

@ -85,7 +85,7 @@ class GraphQlMetricsInstrumentationTests {
Timer timer = this.registry.find("graphql.request").timer();
assertThat(timer).isNotNull();
assertThat(timer.takeSnapshot().count()).isEqualTo(1);
assertThat(timer.count()).isEqualTo(1);
}
@Test
@ -120,7 +120,7 @@ class GraphQlMetricsInstrumentationTests {
Timer timer = this.registry.find("graphql.datafetcher").timer();
assertThat(timer).isNotNull();
assertThat(timer.takeSnapshot().count()).isEqualTo(1);
assertThat(timer.count()).isEqualTo(1);
}
@Test
@ -135,7 +135,7 @@ class GraphQlMetricsInstrumentationTests {
Timer timer = this.registry.find("graphql.datafetcher").timer();
assertThat(timer).isNotNull();
assertThat(timer.takeSnapshot().count()).isEqualTo(1);
assertThat(timer.count()).isEqualTo(1);
}
@Test
@ -150,7 +150,7 @@ class GraphQlMetricsInstrumentationTests {
Timer timer = this.registry.find("graphql.datafetcher").timer();
assertThat(timer).isNotNull();
assertThat(timer.takeSnapshot().count()).isEqualTo(1);
assertThat(timer.count()).isEqualTo(1);
}
@Test

@ -168,7 +168,7 @@ class GraphQlWebMvcSecurityAutoConfigurationTests {
}
@Bean
static InMemoryUserDetailsManager userDetailsService() {
InMemoryUserDetailsManager userDetailsService() {
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build();
UserDetails admin = userBuilder.username("admin").password("admin").roles("USER", "ADMIN").build();

@ -905,7 +905,7 @@ A single GraphQL query can involve many `DataFetcher` calls, so there is a dedic
The `graphql.request.datafetch.count` https://micrometer.io/docs/concepts#_distribution_summaries[distribution summary] counts the number of non-trivial `DataFetcher` calls made per request.
This metric is useful for detecting "N+1" data fetching issues and consider batch loading; it provides the `"TOTAL"` number of data fetcher calls made over the `"COUNT"` of recorded requests, as well as the `"MAX"` calls made for a single request over the considered period.
This metric is useful for detecting "N+1" data fetching issues and considering batch loading; it provides the `"TOTAL"` number of data fetcher calls made over the `"COUNT"` of recorded requests, as well as the `"MAX"` calls made for a single request over the considered period.
More options are available for <<application-properties#application-properties.actuator.management.metrics.distribution.maximum-expected-value, configuring distributions with application properties>>.
A single response can contain many GraphQL errors, counted by the `graphql.error` counter:

@ -49,7 +49,7 @@ You can declare `RuntimeWiringConfigurer` beans in your Spring config to get acc
Spring Boot detects such beans and adds them to the {spring-graphql-docs}#execution-graphqlsource[GraphQlSource builder].
Typically, however, applications will not implement `DataFetcher` directly and will instead create {spring-graphql-docs}#controllers[annotated controllers].
Spring Boot will automatically register `@Controller` classes with annotated handler methods and registers those as `DataFetcher`s.
Spring Boot will automatically detect `@Controller` classes with annotated handler methods and register those as `DataFetcher`s.
Here's a sample implementation for our greeting query with a `@Controller` class:
[source,java,indent=0,subs="verbatim"]

@ -25,11 +25,11 @@ import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
@Controller
public class ProjectsController {
public class ProjectController {
private final List<Project> projects;
public ProjectsController() {
public ProjectController() {
this.projects = Arrays.asList(new Project("spring-boot", "Spring Boot"),
new Project("spring-graphql", "Spring GraphQL"), new Project("spring-framework", "Spring Framework"));
}

@ -28,13 +28,13 @@ import org.springframework.security.web.DefaultSecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Bean
DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) throws Exception {
public DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) throws Exception {
return http.csrf((csrf) -> csrf.disable())
// Demonstrate that method security works
// Best practice to use both for defense in depth
@ -43,7 +43,7 @@ public class SecurityConfig {
@Bean
@SuppressWarnings("deprecation")
public static InMemoryUserDetailsManager userDetailsService() {
public InMemoryUserDetailsManager userDetailsService() {
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build();
UserDetails admin = userBuilder.username("admin").password("admin").roles("USER", "ADMIN").build();

@ -22,7 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
import org.springframework.graphql.test.tester.GraphQlTester;
@GraphQlTest(ProjectsController.class)
@GraphQlTest(ProjectController.class)
class ProjectControllerTests {
@Autowired

Loading…
Cancel
Save