使用 Spring Boot 创建 GraphQL API

GraphQL 是啥?

根据其 官方文档,“GraphQL 是一种用于 API 的查询语言,也是一种服务器端运行时,可使用你为数据定义的类型系统来执行查询”。该语言由 Meta 公司开发并开源,目前由众多公司和个人社区共同维护。

GraphQL 包括 2 个主要部分:

  1. Schema Definition Language(Schema 定义语言) - 使用 GraphQL SDL(Schema 定义语言)指定服务的 GraphQL Schema,有时也称为 GraphQL Schema 语言。
  2. Query Language(查询语言) - 查询语言由Query、Mutation 和 Subscription 三部分组成

本文稍后会进行介绍。

GraphQL 有很多出色的功能,例如:

  1. 它实现了声明式数据获取,并提供了一个单一的端点,客户端可以准确地指定所需的信息,不再需要过度获取信息。
  2. 它提供开箱即用的验证和类型检查功能,你可以在执行前在 GraphQL 强类型系统中验证查询。
  3. GraphQL 可以使 API 文档与 API 的更改保持同步。这对开发人员非常有益,因为他们无需花费太多时间来编写 API 文档。
  4. GraphQL 通过在字段级别废除 API,消除了对版本控制的需求。旧字段可以在不影响现有查询的情况下从 Schema 中删除。

也有一些缺点:

  1. GraphQL 需要客户端和服务器端更多的工具支持。这需要大量的前期付出。对于非常简单的 API 用例来说,这不是一个合适的替代方案。
  2. GrpahQL 只有一个入口,默认使用 HTTP POST。这就妨碍了客户端 HTTP 缓存的充分使用,并使得实现缓存成为一项相对复杂的任务。

GraphQL Schema

GraphQL 服务必须使用 Schema。GraphQL Schema 定义了如何从服务器请求和返回数据,并由 GraphQL SDL 控制。

让我们通过一个示例 Schema 来了解一些最重要的概念:

# root Query Type
type Query {
    fetchBooks: [Book]
}

# Book type
type Book {
    id : ID
    name : String
    author: String
    ratings: [Rating]
}

# Rating type
type Rating {
    id: ID
    rating: Int
    comment: String
    user: String
}

对象类型:对象类型是 GraphQL 服务特有的,使用 type 关键字定义。它们定义了类型名称和该类型下的字段。对象类型中的每个字段都可以解析为标量类型或其他对象类型,例如,Book 类型有 String 类型的标量字段和 Rating 类型的另一个对象字段。

内置标量类型:raphQL 中有 5 种内置标量类型: IntFloatStringBooleanIDID 类型解析为字符串,但期望值是唯一的。

类型修饰符:修饰符可通过使用 [...] 等字符用于字段解析的类型,例如,root Query 的类型修饰符为 [Book],它表示由不可为 null 的字符串值组成的可为空列表。整个值可以为 null,或者特定的列表元素可以为 null。

操作:GraphQL 服务可支持以下操作:

  1. Queries:Queries 表示 READ 操作。
  2. Mutation:Mutation 包括先写入(WRITE)然后读取(READ)的操作。
  3. Subscription:Subscription 用于连续读取(如通过 WebSocket)。

开始

在本文中,我们使用 Spring Boot GraphQL 构建一个 book catalog(图书目录)服务。该服务支持一个名为 fetchBooks 的查询,用于返回所有时间中排名前 5 的书籍(book)、作者(author)和评分(rating)。

使用 Spring for GraphQL 构建这项服务。它基于 GraphQL Java 构建,支持通过 HTTP 和 WebSocket 处理 GraphQL 请求。GraphQL 规范与任何传输层协议无关。我使用 GraphQL over HTTP 规范构建此 API。

在深入研究代码之前,让我们先花点时间了解一下 Spring GraphQL。

它有 3 个主要组件:Transport、GraphQL Java 引擎和 Data fetcher(数据获取器)。

Spring GraphQL 的 3 个主要组件

Transport:GraphQL Java 默认不提供任何传输机制。你可以使用 Spring 框架提供的任何传输机制,例如 Spring MVC、Spring WebFlux 和 WebSocket 等。这些处理器会将所有请求传送到 GraphQL Java 引擎。

GraphQL Java Engine:它支持从头开始引导服务,并支持从 Web 层到数据层的上下文传播。异常也在这一层进行处理。

Data Fetchers:它提供注解 Controller(@Controller)、Query Domain Specific Language(DSL)和 Repository。

实现服务

1、创建 Spring Boot 项目

你可以使用 Spring Initializer 创建一个空的 Spring Boot 项目,并包含以下依赖:

Spring Initializer

  • spring-boot-starter-graphql:主要的依赖
  • spring-boot-starter-web:构建传输层(transport )

2、为 books catalog 服务创建 Schema 文件

type Query {
    fetchBooks: [Book]
}

type Book {
    id : ID
    name : String
    author: String
    ratings: [Rating]
}

type Rating {
    id: ID
    rating: Int
    comment: String
    user: String
}

3、创建 data fetcher

Data fetcher 是一个回调函数,它获取的数据包括查询结果。当收到传入的 GraphQL 查询时,库将调用已注册的查询 DataFetcher。每个查询都必须有一个关联的 DataFetcher,例如,在第 2 步中定义的 schema 中,我们 为 “fetchBooks” 查询创建一个 data fetcher。

4、和 RunTimewiring 进行关联

GraphQL Java 使用 RuntimeWiring builder 来注册 data fetcher、type resolver(类型解析器)等。我们在 Spring 配置中创建 RuntimeWiringConfigurer Bean,以便访问 RuntimeWiring.Builder。下面的代码片段展示了用于 “fetchBooks” 查询的 data fetcher,并将其与 RuntimeWiring builder 进行关联。

@Configuration
public class GraphQLServiceConfiguration {

    @Bean
    public RuntimeWiringConfigurer runtimeWiringConfigurer(BooksCatalogService bookCatalogService) {
        return builder -> {
            builder.type(
                    "Query",
                    wiring ->
                            wiring
                                    .dataFetcher("fetchBooks", environment -> bookCatalogService.fetchBooks()));
            builder.type(
                    "Book",
                    wiring ->
                            wiring.dataFetcher("ratings", env -> bookCatalogService.fetchRatings(env.getSource())));
        };
    }
}

在上述代码中,字段 fetchBooks 的 Data Fetcher 通过调用 books catalog 服务的 fetchBooks()fetchRatings() 方法获取所有书籍和评分(rating)。

5、运行和测试

你可以通过运行 BooksCatalogServiceApplication 类的 main 方法,在 IDE 中启动 GraphQL 服务:

IDE 中启动 GraphQL 服务

你可以使用 Insomnia 客户端测试你的 API。

POST:http://localhost:8080/graphql

使用 Insomnia 客户端测试 GraphQL API

也可以通过 http://localhost:8080/graphiql?path=/graphql 在浏览器中使用 GraphiQL 编辑器。

GraphiQL 编辑器

要启用 GraphiQL 编辑器,必须在 application.properties 中设置 spring.graphql.graphiql.enabled=true

完整的示例代码托管在 GitHub,你可以 clone 到本地,在IDE 中导入 books-catalog-service Maven 项目。


参考:https://dev.to/aparoha/how-to-write-graphql-apis-in-spring-boot-a-beginners-guide-2bc3