Merge branch '1.0.x'
This commit is contained in:
@@ -154,15 +154,12 @@ public class GraphQlRSocketController {
|
||||
[[server-interception]]
|
||||
=== Interception
|
||||
|
||||
Spring MVC and Spring WebFlux transport handlers, for both <<server-http>> and
|
||||
<<server-websocket>>, all delegate to the same `WebGraphQlInterceptor` chain, followed by
|
||||
the `ExecutionGraphQlService` that invokes the GraphQL Java engine. You can use this to
|
||||
intercept GraphQL requests over any Web transport.
|
||||
Transport handlers for <<server-http>> and <<server-websocket>> delegate to a
|
||||
`WebGraphQlInterceptor` chain with an `ExecutionGraphQlService` at the end which calls
|
||||
the GraphQL Java engine. Use this to access HTTP request details and customize the
|
||||
`ExecutionInput` for GraphQL Java.
|
||||
|
||||
A `WebGraphQlInterceptor` exposes the details of the underlying transport (HTTP or
|
||||
WebSocket handshake) request and allows customizing the `graphql.ExecutionInput`
|
||||
that is prepared for GraphQL Java. For example, to extract an HTTP header and make it
|
||||
available to data fetchers through the `GraphQLContext`:
|
||||
For example, to extract HTTP request values and pass them to data fetchers:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -170,16 +167,26 @@ class HeaderInterceptor implements WebGraphQlInterceptor {
|
||||
|
||||
@Override
|
||||
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
|
||||
List<String> headerValue = request.getHeaders().get("myHeader");
|
||||
List<String> values = request.getHeaders().get("headerName");
|
||||
request.configureExecutionInput((executionInput, builder) ->
|
||||
builder.graphQLContext(Collections.singletonMap("myHeader", headerValue)).build());
|
||||
builder.graphQLContext(Collections.singletonMap("headerName", values)).build());
|
||||
return chain.next(request);
|
||||
}
|
||||
}
|
||||
|
||||
// Subsequent access from a controller
|
||||
|
||||
@Controller
|
||||
class MyController {
|
||||
|
||||
@QueryMapping
|
||||
Person person(@ContextValue String myHeader) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
A `DataFetcher` can then access this value, e.g. from an
|
||||
<<controllers,annotated controller>> method:
|
||||
Or reversely, add values to the `GraphQLContext` and use them to update the HTTP response:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -187,34 +194,28 @@ A `DataFetcher` can then access this value, e.g. from an
|
||||
class MyController {
|
||||
|
||||
@QueryMapping
|
||||
Person person(@ContextValue String myHeader) {
|
||||
// ...
|
||||
Person person(GraphQLContext context) {
|
||||
context.put("cookieName", "123");
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
// Subsequent access from a WebGraphQlInterceptor
|
||||
|
||||
Interceptors can also customize HTTP response headers, or inspect and/or transform the
|
||||
`graphql.ExecutionResult` from GraphQL Java:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
class MyInterceptor implements WebGraphQlInterceptor {
|
||||
class HeaderInterceptor implements WebGraphQlInterceptor {
|
||||
|
||||
@Override
|
||||
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
|
||||
return chain.next(request)
|
||||
.map(response -> {
|
||||
Object data = response.getData();
|
||||
Object updatedData = ... ;
|
||||
return response.transform(builder -> builder.data(updatedData));
|
||||
});
|
||||
return chain.next(request).doOnNext(response -> {
|
||||
String value = response.getExecutionInput().getGraphQLContext().get("cookieName");
|
||||
ResponseCookie cookie = ResponseCookie.from("cookieName", value).build();
|
||||
response.getResponseHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
`WebGraphQlHandler` has a builder to create the `WebGraphQlInterceptor` chain. The Boot
|
||||
starter uses this, see Boot's section on
|
||||
The `WebGraphQlInterceptor` chain can be updated through the `WebGraphQlHandler` builder,
|
||||
and the Boot starter uses this, see Boot's section on
|
||||
{spring-boot-ref-docs}/web.html#web.graphql.web-endpoints[Web Endpoints].
|
||||
|
||||
The <<server-rsocket>> transport handler delegates to a similar `GraphQlInterceptor`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -26,8 +26,8 @@ import graphql.schema.DataFetchingEnvironment;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.graphql.data.method.HandlerMethodArgumentResolver;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Resolver for the source/parent of a field, obtained via
|
||||
@@ -66,10 +66,21 @@ public class SourceMethodArgumentResolver implements HandlerMethodArgumentResolv
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) {
|
||||
Object source = environment.getSource();
|
||||
Assert.isInstanceOf(parameter.getParameterType(), source,
|
||||
"The declared parameter of type '" + parameter.getParameterType() + "' " +
|
||||
"does not match the type of the source Object '" + source.getClass() + "'.");
|
||||
if (source == null) {
|
||||
throw new IllegalStateException(formatArgumentError(parameter,
|
||||
" was not recognized by any resolver and there is no source/parent either. " +
|
||||
"Please, refer to the documentation for the full list of supported parameters."));
|
||||
}
|
||||
if (!parameter.getParameterType().isInstance(source)) {
|
||||
throw new IllegalStateException(formatArgumentError(parameter,
|
||||
" does not match the source Object type '" + source.getClass() + "'."));
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
private static String formatArgumentError(MethodParameter param, String message) {
|
||||
return "Parameter [" + param.getParameterIndex() + "] in " +
|
||||
param.getExecutable().toGenericString() + (StringUtils.hasText(message) ? ": " + message : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user