Spring for GraphQL

如果你想構建 GraphQL 應用,可以利用 Spring Boot 為 Spring for GraphQL 提供的自動配置。Spring for GraphQL 專案基於 GraphQL Java 構建。至少你需要新增 spring-boot-starter-graphql starter。因為 GraphQL 與傳輸層無關,你還需要在應用中包含一個或多個額外的 starter,以便透過 Web 暴露你的 GraphQL API。

Starter 傳輸方式 實現

spring-boot-starter-web

HTTP

Spring MVC

spring-boot-starter-websocket

WebSocket

用於 Servlet 應用的 WebSocket

spring-boot-starter-webflux

HTTP, WebSocket

Spring WebFlux

spring-boot-starter-rsocket

TCP, WebSocket

基於 Reactor Netty 的 Spring WebFlux

GraphQL Schema

Spring GraphQL 應用在啟動時需要定義 schema。預設情況下,你可以在 src/main/resources/graphql/** 目錄下編寫 ".graphqls" 或 ".gqls" schema 檔案,Spring Boot 會自動載入它們。你可以使用 spring.graphql.schema.locations 定製位置,使用 spring.graphql.schema.file-extensions 定製副檔名。

如果你想讓 Spring Boot 檢測所有應用模組和依賴中該位置的 schema 檔案,可以將 spring.graphql.schema.locations 設定為 "classpath*:graphql/**/"(注意 classpath*: 字首)。

在以下章節中,我們將使用這個示例 GraphQL schema,它定義了兩個型別和兩個查詢

type Query {
    greeting(name: String! = "Spring"): String!
    project(slug: ID!): Project
}

""" A Project in the Spring portfolio """
type Project {
    """ Unique string id used in URLs """
    slug: ID!
    """ Project name """
    name: String!
    """ URL of the git repository """
    repositoryUrl: String!
    """ Current support status """
    status: ProjectStatus!
}

enum ProjectStatus {
    """ Actively supported by the Spring team """
    ACTIVE
    """ Supported by the community """
    COMMUNITY
    """ Prototype, not officially supported yet  """
    INCUBATING
    """ Project being retired, in maintenance mode """
    ATTIC
    """ End-Of-Lifed """
    EOL
}
預設情況下,schema 上允許進行欄位自省(introspection),因為 GraphiQL 等工具需要它。如果你不想暴露 schema 的資訊,可以透過將 spring.graphql.schema.introspection.enabled 設定為 false 來停用自省。

GraphQL RuntimeWiring

GraphQL Java 的 RuntimeWiring.Builder 可用於註冊自定義標量型別、指令、型別解析器、DataFetcher 等。你可以在 Spring 配置中宣告 RuntimeWiringConfigurer bean 來獲取 RuntimeWiring.Builder。Spring Boot 會檢測這些 bean 並將其新增到 GraphQlSource 構建器中。

通常,應用不會直接實現 DataFetcher,而是建立註解控制器。Spring Boot 會自動檢測帶有註解處理方法的 @Controller 類,並將它們註冊為 DataFetcher。以下是使用 @Controller 類實現的 greeting 查詢示例

  • Java

  • Kotlin

import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;

@Controller
public class GreetingController {

	@QueryMapping
	public String greeting(@Argument String name) {
		return "Hello, " + name + "!";
	}

}
import org.springframework.graphql.data.method.annotation.Argument
import org.springframework.graphql.data.method.annotation.QueryMapping
import org.springframework.stereotype.Controller

@Controller
class GreetingController {

	@QueryMapping
	fun greeting(@Argument name: String): String {
		return "Hello, $name!"
	}

}

Querydsl 和 QueryByExample Repository 支援

Spring Data 支援 Querydsl 和 QueryByExample Repository。Spring GraphQL 可以將 Querydsl 和 QueryByExample Repository 配置為 DataFetcher

@GraphQlRepository 註解並繼承以下介面之一的 Spring Data Repository

會被 Spring Boot 檢測到,並被視為匹配頂級查詢的 DataFetcher 候選。

傳輸方式

HTTP 和 WebSocket

GraphQL HTTP 端點預設為 HTTP POST /graphql。它也支援透過 Server Sent Events(SSE)使用 "text/event-stream" 媒體型別,但僅限於訂閱。路徑可以透過 spring.graphql.path 定製。

Spring MVC 和 Spring WebFlux 的 HTTP 端點都由一個 @Order 為 0 的 RouterFunction bean 提供。如果你定義自己的 RouterFunction bean,你可能需要新增適當的 @Order 註解以確保它們正確排序。

GraphQL WebSocket 端點預設關閉。要啟用它:

  • 對於 Servlet 應用,新增 WebSocket starter spring-boot-starter-websocket

  • 對於 WebFlux 應用,無需額外依賴

  • 對於兩者,都必須設定 spring.graphql.websocket.path 應用屬性

Spring GraphQL 提供了 Web 攔截模型。這對於從 HTTP 請求頭中檢索資訊並將其設定到 GraphQL 上下文,或從同一上下文中獲取資訊並將其寫入響應頭非常有用。使用 Spring Boot,你可以宣告一個 WebGraphQlInterceptor bean,以便將其註冊到 web 傳輸中。

Spring MVCSpring WebFlux 支援 CORS(跨域資源共享)請求。CORS 對於從不同域瀏覽器訪問的 GraphQL 應用來說是 web 配置的關鍵部分。

Spring Boot 支援 spring.graphql.cors.* 名稱空間下的許多配置屬性;以下是一個簡單的配置示例

  • Properties

  • YAML

spring.graphql.cors.allowed-origins=https://example.org
spring.graphql.cors.allowed-methods=GET,POST
spring.graphql.cors.max-age=1800s
spring:
  graphql:
    cors:
      allowed-origins: "https://example.org"
      allowed-methods: GET,POST
      max-age: 1800s

RSocket

RSocket 也支援作為一種傳輸方式,可以基於 WebSocket 或 TCP。一旦RSocket 伺服器配置完成,我們可以使用 spring.graphql.rsocket.mapping 在特定路由上配置我們的 GraphQL handler。例如,將該對映配置為 "graphql" 意味著在使用 RSocketGraphQlClient 傳送請求時,我們可以使用該路由。

Spring Boot 會自動配置一個 RSocketGraphQlClient.Builder bean,你可以將其注入到你的元件中。

  • Java

  • Kotlin

@Component
public class RSocketGraphQlClientExample {

	private final RSocketGraphQlClient graphQlClient;

	public RSocketGraphQlClientExample(RSocketGraphQlClient.Builder<?> builder) {
		this.graphQlClient = builder.tcp("example.spring.io", 8181).route("graphql").build();
	}
@Component
class RSocketGraphQlClientExample(private val builder: RSocketGraphQlClient.Builder<*>) {

然後傳送請求:include-code::RSocketGraphQlClientExample[tag=request]

異常處理

Spring GraphQL 允許應用註冊一個或多個按順序呼叫的 Spring DataFetcherExceptionResolver 元件。異常必須解析為 GraphQLError 物件的列表,請參閱Spring GraphQL 異常處理文件。Spring Boot 會自動檢測 DataFetcherExceptionResolver bean 並將其註冊到 GraphQlSource.Builder

GraphiQL 和 Schema Printer

Spring GraphQL 提供了基礎設施,幫助開發者消費或開發 GraphQL API。

Spring GraphQL 預設自帶一個 GraphiQL 頁面,預設暴露在 "/graphiql"。該頁面預設停用,可以透過 spring.graphql.graphiql.enabled 屬性開啟。許多暴露此類頁面的應用會更喜歡自定義構建。預設實現對於開發期間非常有用,這就是為什麼在開發期間使用 spring-boot-devtools 會自動暴露它。

spring.graphql.schema.printer.enabled 屬性啟用時,你也可以選擇在 /graphql/schema 處暴露文字格式的 GraphQL schema。