Spring for GraphQL 支持服务器通过 HTTP、WebSocket 和 RSocket。
HTTP的
GraphQlHttpHandler
处理 GraphQL over HTTP 请求,并委托给 Interception 链执行请求。有两种变体,一种用于
Spring MVC 和一个用于 Spring WebFlux 的 MVC。两者都异步处理请求,并且具有
等效功能,但分别依赖于阻塞和非阻塞 I/O
编写 HTTP 响应。
请求必须使用 HTTP POST 作为内容类型和 GraphQL 请求详细信息
作为 JSON 包含在请求正文中,如建议的 GraphQL over HTTP 规范中所定义。
成功解码 JSON 正文后,HTTP 响应状态始终为 200 (OK),
GraphQL 请求执行的任何错误都显示在 GraphQL 响应的“错误”部分。
媒体类型的默认和首选选择是 ,但也受支持,如规范中所述。"application/json"
"application/graphql-response+json"
"application/json"
GraphQlHttpHandler
可以通过声明 bean 并使用 from Spring MVC 或 WebFlux 创建路由来公开为 HTTP 端点。Boot Starter 执行此操作,请参阅 Web 终结点部分
详细信息,或检查或它包含实际配置。RouterFunction
RouterFunctions
GraphQlWebMvcAutoConfiguration
GraphQlWebFluxAutoConfiguration
默认情况下,将使用 (Spring MVC) 序列化和反序列化 JSON 有效负载
以及在 Web 框架中配置的 (WebFlux)。
在某些情况下,应用程序会以与 GraphQL 有效负载不兼容的方式为 HTTP 终结点配置 JSON 编解码器。
应用程序可以使用将用于 GraphQL 有效负载的自定义 JSON 编解码器进行实例化。GraphQlHttpHandler
HttpMessageConverter
DecoderHttpMessageReader/EncoderHttpMessageWriter
GraphQlHttpHandler
此存储库的 1.0.x 分支包含一个 Spring MVC HTTP 示例应用程序。
服务器发送的事件
GraphQlSseHandler
与上面列出的 HTTP 处理程序非常相似,但这次通过 HTTP 处理 GraphQL 请求
使用服务器发送事件协议。使用此传输,客户端必须将 HTTP POST 请求发送到端点,并将内容类型和 GraphQL 请求详细信息作为 JSON 包含在请求正文中;唯一的
与普通 HTTP 变体的区别在于客户端必须作为请求发送
页眉。响应将作为一个或多个服务器发送事件发送。"application/json"
"text/event-stream"
"Accept"
这也在提议的 GraphQL over HTTP 规范中定义。 Spring for GraphQL 仅实现“不同连接模式”,因此应用程序必须考虑可伸缩性问题 以及采用 HTTP/2 作为底层传输是否有帮助。
主要用例是 WebSocket 传输的替代方案,接收项目流作为对
订阅操作。此处不支持其他类型的操作,例如查询和突变,并且应该支持
使用基于 HTTP 传输变体的纯 JSON。GraphQlSseHandler
文件上传
作为一种协议,GraphQL 专注于文本数据的交换。这不包括二进制文件 数据,例如图像,但有一个单独的、非正式的 graphql-multipart-request-spec,允许使用 GraphQL over HTTP 上传文件。
Spring for GraphQL 不支持直接。
虽然该规范确实提供了统一的 GraphQL API 的好处,但实际经验具有
导致了许多问题,并且最佳实践建议已经发展,有关更详细的讨论,请参阅 Apollo Server 文件上传最佳实践。graphql-multipart-request-spec
如果您想在应用程序中使用,您可以
通过库 multipart-spring-graphql 执行此操作。graphql-multipart-request-spec
网络套接字
GraphQlWebSocketHandler
根据 graphql-ws 库中定义的协议处理 GraphQL over WebSocket 请求。使用的主要原因
GraphQL over WebSocket 是允许发送 GraphQL 流的订阅
响应,但它也可用于具有单个响应的常规查询。
处理程序将每个请求委托给 Interception 链,以便进一步
请求执行。
基于 WebSocket 协议的 GraphQL
有两个这样的协议,一个在 subscriptions-transport-ws 库中,另一个在 graphql-ws 库中。前者不活跃且 继任者是后者。阅读这篇博文了解历史。 |
有两种变体,一种用于 Spring MVC,另一种用于
Spring WebFlux 中。两者都异步处理请求,并具有等效的功能。
WebFlux 处理程序还使用非阻塞 I/O 和背压来流式传输消息,
这很好用,因为在 GraphQL Java 中,订阅响应是 反应式流 .GraphQlWebSocketHandler
Publisher
该项目列出了许多供客户使用的配方。graphql-ws
GraphQlWebSocketHandler
可以通过声明 Bean 并使用它来将处理程序映射到 URL 路径来公开为 WebSocket 端点。默认情况下,
Boot Starter 不会公开 GraphQL over WebSocket 端点,
但您可以为终结点路径添加属性以启用它。请查看启动参考文档中的 Web 终结点以及支持的属性列表。
您还可以查看或“GraphQlWebFluxAutoConfiguration”
了解实际的引导自动配置详细信息。SimpleUrlHandlerMapping
spring.graphql.websocket
GraphQlWebMvcAutoConfiguration
此存储库的 1.0.x 分支包含一个 WebFlux WebSocket 示例应用程序。
基于 WebSocket 协议的 GraphQL
有两个这样的协议,一个在 subscriptions-transport-ws 库中,另一个在 graphql-ws 库中。前者不活跃且 继任者是后者。阅读这篇博文了解历史。 |
RSocket
GraphQlRSocketHandler
处理 GraphQL over RSocket 请求。查询和突变是
预期并作为 RSocket 交互处理,而订阅是
处理为 .request-response
request-stream
GraphQlRSocketHandler
可以使用映射到
GraphQL 请求的路由。例如:@Controller
import java.util.Map;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.graphql.server.GraphQlRSocketHandler;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.stereotype.Controller;
@Controller
public class GraphQlRSocketController {
private final GraphQlRSocketHandler handler;
GraphQlRSocketController(GraphQlRSocketHandler handler) {
this.handler = handler;
}
@MessageMapping("graphql")
public Mono<Map<String, Object>> handle(Map<String, Object> payload) {
return this.handler.handle(payload);
}
@MessageMapping("graphql")
public Flux<Map<String, Object>> handleSubscription(Map<String, Object> payload) {
return this.handler.handleSubscription(payload);
}
}
拦截
服务器传输允许在 GraphQL Java 引擎之前和之后拦截请求 调用以处理请求。
WebGraphQlInterceptor
HTTP 和 WebSocket 传输调用 0 或更多个链,后跟一个调用 GraphQL Java 引擎的链。
拦截器允许应用程序拦截传入请求,以便:WebGraphQlInterceptor
ExecutionGraphQlService
-
检查 HTTP 请求详细信息
-
自定义
graphql.ExecutionInput
-
添加 HTTP 响应标头
-
自定义
graphql.ExecutionResult
-
和更多
例如,拦截器可以将 HTTP 请求标头传递给:DataFetcher
import java.util.Collections;
import reactor.core.publisher.Mono;
import org.springframework.graphql.data.method.annotation.ContextValue;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.server.WebGraphQlInterceptor;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.stereotype.Controller;
class RequestHeaderInterceptor implements WebGraphQlInterceptor { (1)
@Override
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
String value = request.getHeaders().getFirst("myHeader");
request.configureExecutionInput((executionInput, builder) ->
builder.graphQLContext(Collections.singletonMap("myHeader", value)).build());
return chain.next(request);
}
}
@Controller
class MyContextValueController { (2)
@QueryMapping
Person person(@ContextValue String myHeader) {
...
}
}
1 | Interceptor 将 HTTP 请求标头值添加到 GraphQLContext 中 |
2 | 数据控制器方法访问值 |
相反,拦截器可以访问控制器添加到 的值:GraphQLContext
import graphql.GraphQLContext;
import reactor.core.publisher.Mono;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.server.WebGraphQlInterceptor;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Controller;
// Subsequent access from a WebGraphQlInterceptor
class ResponseHeaderInterceptor implements WebGraphQlInterceptor {
@Override
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) { (2)
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());
});
}
}
@Controller
class MyCookieController {
@QueryMapping
Person person(GraphQLContext context) { (1)
context.put("cookieName", "123");
...
}
}
1 | 控制器为GraphQLContext |
2 | Interceptor 使用该值添加 HTTP 响应标头 |
WebGraphQlHandler
可以修改,例如检查和修改
在执行开始之前引发的请求验证错误,并且不能
处理方式为:ExecutionResult
DataFetcherExceptionResolver
import java.util.List;
import graphql.GraphQLError;
import graphql.GraphqlErrorBuilder;
import reactor.core.publisher.Mono;
import org.springframework.graphql.server.WebGraphQlInterceptor;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
class RequestErrorInterceptor implements WebGraphQlInterceptor {
@Override
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
return chain.next(request).map((response) -> {
if (response.isValid()) {
return response; (1)
}
List<GraphQLError> errors = response.getErrors().stream() (2)
.map((error) -> {
GraphqlErrorBuilder<?> builder = GraphqlErrorBuilder.newError();
// ...
return builder.build();
})
.toList();
return response.transform((builder) -> builder.errors(errors).build()); (3)
});
}
}
1 | 如果具有非 null 值的“data”键,则返回相同的值ExecutionResult |
2 | 检查并转换 GraphQL 错误 |
3 | 使用修改后的错误更新ExecutionResult |
WebSocketGraphQlInterceptor
WebSocketGraphQlInterceptor
使用其他回调进行扩展
除了客户端之外,还处理 WebSocket 连接的开始和结束
取消订阅。同样也会拦截每个 GraphQL 请求
WebSocket 连接。WebGraphQlInterceptor
用于配置链。这是支持的
通过启动启动程序,请参阅 Web 终结点。
在一连串的拦截器中最多可以有一个。WebGraphQlHandler
WebGraphQlInterceptor
WebSocketGraphQlInterceptor
有两个内置的 WebSocket 拦截器称为 ,
一个用于 WebMVC,一个用于 WebFlux 传输。这些有助于提取身份验证
来自 GraphQL over WebSocket 消息、authenticate 的有效负载的详细信息,
然后将 WebSocket 连接上的后续请求传播。AuthenticationWebSocketInterceptor
"connection_init"
SecurityContext
spring-graphql-examples 中有一个 websocket-authentication 示例。 |
RSocketQlInterceptor
与 WebGraphQlInterceptor
类似,允许拦截
GraphQL over RSocket 请求在 GraphQL Java 引擎执行之前和之后。您可以使用
这将自定义 和 .RSocketQlInterceptor
graphql.ExecutionInput
graphql.ExecutionResult
1 | Interceptor 将 HTTP 请求标头值添加到 GraphQLContext 中 |
2 | 数据控制器方法访问值 |
1 | 控制器为GraphQLContext |
2 | Interceptor 使用该值添加 HTTP 响应标头 |
1 | 如果具有非 null 值的“data”键,则返回相同的值ExecutionResult |
2 | 检查并转换 GraphQL 错误 |
3 | 使用修改后的错误更新ExecutionResult |
spring-graphql-examples 中有一个 websocket-authentication 示例。 |