前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Spring for GraphQL 构建 GraphQL API 的步骤

使用 Spring for GraphQL 构建 GraphQL API 的步骤

原创
作者头像
種法龍
发布2024-01-01 14:47:09
1780
发布2024-01-01 14:47:09
举报
文章被收录于专栏:未知未知

要实现的 API 的数据模型


将存储在数据库中的以下表重新定义为 GraphQL 模式,以实现能够获取灵活数据的 API。首先,以下图的数据模型为基础,开始进行 GraphQL 模式的定义。

各表的用途如下。

由于这只是个简单的例子,所以并没有完全规范化,请不要太在意。

  • Account 表:管理用户的账户信息。
  • Service_Group 表:管理用户所属的服务组,而服务组可以拥有多个团队。
  • Team 表:管理用户所属的团队。

创建空白项目


首先,使用 Spring Initializr 创建一个空白项目并创建所需的包和目录。

所使用的构建工具、JDK、Spring Boot 及依赖库如下:

框架/库等

版本

OpenJDK

11

SpringBoot

2.7.1

Maven

3.5.4

Spring Web

-

Spring for GraphQL

-

Lombok

-

H2 Database

-

log4j2

-

此外,由于 Log4j2 不能在 Spring Initializr 中指定,因此需要直接将依赖关系添加到 pom.xml 中。

在这之前,需要通过 <exclusion> 来排除由 spring-boot-starter 依赖的日志库。

代码语言:xml
复制
<dependency>
  <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <exclusions>
      <exclusion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
      </exclusion>
    </exclusions>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

示例应用程序结构


项目结构如下:

代码语言:bat
复制
spring-graphql-sample
 ├ src
 │  ├ main
 │  │  ├ java/com.spring.graphql.example 
 │  │  │  ├ controller
 │  │  │  ├ entity
 │  │  │  ├ repository
 │  │  │  └ Main.java 
 │  │  │
 │  │  └ resources
 │  │     ├ graphql
 │  │     │  └ graphql-schema.graphqls --- GraphQL 文件
 │  │     ├ aplication.yaml
 │  │     ├ log4j2.xml --- 日志输出配置
 │  │     ├ schema.sql --- H2 数据库表初始化脚本
 │  │     └ data.sql  --- H2 数据库数据初始化脚本
 │  │
 │  └ test --- 用于测试(本例未使用)
 └ pom.xml

实现准备


在直接实现 GraphQL API 之前,将对项目进行配置,包括将数据流入数据库和设置日志。

准备工作1:表定义和数据库连接定义设置

因为单独设置每个 DBMS 太麻烦了,所以将使用 H2DB。

为了在应用启动时将表和数据自动导入到 H2DB,将以下内容保存在 schema.sql 中。

(由于省略了 data.sql 的内容,请根据需要自行设置适当的数据)

代码语言:sql
复制
-- Service Group
CREATE TABLE service_group (
  service_group_id VARCHAR(10) PRIMARY KEY COMMENT '服务组ID',
  service_group_name VARCHAR(40) NOT NULL COMMENT '服务组名'
);

-- Team
CREATE TABLE team (
  team_id VARCHAR(10) PRIMARY KEY COMMENT '团队ID',
  belonging_service_group_id VARCHAR(10) NOT NULL COMMENT '所属服务组ID',
  team_name VARCHAR(40) NOT NULL COMMENT '团队名',
  team_authority VARCHAR(15) COMMENT '团队权限',
  FOREIGN KEY (belonging_service_group_id) REFERENCES service_group (service_group_id)
);

-- Account Table
CREATE TABLE account (
  account_id VARCHAR(10) PRIMARY KEY COMMENT '账户ID',
  user_name VARCHAR(40) NOT NULL COMMENT '用户名',
  age INT NOT NULL COMMENT '年龄',
  account_type VARCHAR(10) NOT NULL COMMENT '账户分类',
  belonging_service_group_id VARCHAR(10) NOT NULL COMMENT '所属服务组ID',
  belonging_team_id VARCHAR(10) NOT NULL COMMENT '所属团队ID',
  FOREIGN KEY (belonging_service_group_id) REFERENCES service_group (service_group_id),
  FOREIGN KEY (belonging_team_id) REFERENCES team (team_id)
);

接下来,将在 application.yaml 文件中进行数据库连接的定义设置。

代码语言:yaml
复制
spring:
  datasource:
    platform: h2
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=1;DB_CLOSE_ON_EXIT=FALSE;MODE=DB2
    username: sa
    password: ''

准备工作2:日志设置


将使用 log4j2 进行日志记录。

代码语言:xml
复制
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error">

    <Properties>
        <Property name="format1">[%d{yyyy/MM/dd HH:mm:ss.SSS}] [%t] [%-6p] [%c{10}] : %m%n</Property>
    </Properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout>
                <pattern>${format1}</pattern>
            </PatternLayout>
        </Console>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>

GraphQL API 实现


前期准备工作已完成,现在将开始实现主题的 GraphQL API。

步骤1:定义 GraphQL 模式


在 resources/graphql/ 中创建一个名为 graphql-schema.graphqls 的文件,并定义 GraphQL 模式和查询。

在这个例子中,将定义一个名为 accountById 的查询。

该查询允许通过将账户ID作为参数发送到API请求,获取与账户ID关联的账户信息,以及该账户所属的服务组信息和团队信息。

虽然没有太多实际意义,但还可以从获取的团队信息中获取团队所属的服务组信息。

GraphQL 模式的定义与数据库表定义不同,推荐以数据使用者易于理解的形式定义模式。

关于模式定义的规则和思考方式,请参考这个链接

代码语言:GraphQL
复制
# クエリ定義
type Query {
    accountById(accountId: ID): Account
}
# タイプ定義
type ServiceGroup {
    serviceGroupId: ID!
    serviceGroupName: String
    teams: [Team]
}
type Team {
    teamId: ID!
    teamName: String
    teamAuthority: String
    serviceGroup: ServiceGroup!
}
type Account {
    accountId: ID!
    userName: String
    age: Int
    accountType: String
    serviceGroup: ServiceGroup!
    team: Team!
}

# Enum定義
enum TeamAuthority {
    PRIVILEGE
    DEVELOP
    AUDIT
}
enum AccountType {
    ADMIN
    DEVELOPER
    GUEST
}

步骤2:实现 DTO 类


创建用于存储从数据库中检索的数据的 DTO 类,并将其放置在 entity 包中。

由于定义了三个表,因此将创建每个表的DTO类。

此外,为了避免繁琐地编写 Setter/Getter,使用了 Lombok。

对于主键和关联变量,使用 @Id 注解。

代码语言:java
复制
Account.java
@Setter
@Getter
@AllArgsConstructor
public class Account {
    @Id
    private String accountId;
    private String userName;
    private int age;
    private String accountType;
    private String belongingServiceGroupId;
    private String belongingTeamId;
}
代码语言:java
复制
ServiceGroup.java
@Setter
@Getter
public class ServiceGroup {
    @Id
    private String serviceGroupId;
    private String serviceGroupName;
}
代码语言:java
复制
@Setter
@Getter
public class Team {
    @Id
    private String teamId;
    private String belongingServiceGroupId;
    private String teamName;
    private String teamAuthority;
}

步骤3:实现 Repository 接口


将使用 Spring Data JDBC 与数据库进行交互。

实现与每个表对应的 Repository 接口,并将其存储在 repository 包中。

(由于这次是简单的表结构,按表分别实现接口。)

通过 extends 指定的 CrudRepository 已经默认提供了 findById 方法,因此在以主键作为参数检索数据时,不需要单独实现数据库查询。

代码语言:java
复制
public interface AccountRepository extends CrudRepository<Account, String>{
}
代码语言:java
复制
public interface ServiceGroupRepository extends CrudRepository<ServiceGroup, String> {
}

对于 TeamRepository,由于需要实现除主键之外的参数的 SELECT 查询,因此需要按照以下示例定义方法。

代码语言:java
复制
public interface TeamRepository extends CrudRepository<Team, String> {

    @Query("SELECT team_id, belonging_service_group_id, team_name, team_authority" +
            " FROM team WHERE belonging_service_group_id = :serviceGroupId")
    List<Team> findByServiceGroupId(String serviceGroupId);
}

步骤4:实现 Controller 类

代码语言:java
复制
@Controller
public class AccountGraphqlController {

    private final Logger logger = LogManager.getLogger(AccountGraphqlController.class);

    private AccountRepository accountRepository;

    private ServiceGroupRepository serviceGroupRepository;

    private TeamRepository teamRepository;

    public AccountGraphqlController(final AccountRepository accountRepository,
                                    final ServiceGroupRepository serviceGroupRepository,
                                    final TeamRepository teamRepository) {
        this.accountRepository = accountRepository;
        this.serviceGroupRepository = serviceGroupRepository;
        this.teamRepository = teamRepository;
    }

    @QueryMapping
    public Account accountById(@Argument final String accountId) {
        logger.info("=== Query Call, queryByAccountId. === ");
        final Optional<Account> acc = accountRepository.findById(accountId);
        return acc.get();
    }

    @SchemaMapping
    public ServiceGroup serviceGroup(final Account account) {
        final Optional<ServiceGroup> sg = serviceGroupRepository.findById(account.getBelongingServiceGroupId());
        return sg.get();
    }

    @SchemaMapping
    public Team team(final Account account) {
        final Optional<Team> t = teamRepository.findById(account.getBelongingTeamId());
        return t.get();
    }

    @SchemaMapping
    public ServiceGroup serviceGroup(final Team team) {
        final Optional<ServiceGroup> sg = serviceGroupRepository.findById(team.getBelongingServiceGroupId());
        return sg.get();
    }
}

步骤5:配置 GraphQL 端点 URL


在 application.yaml 文件中进行 GraphQL API 端点路径的配置和启用。

代码语言:yml
复制
spring:
  # 省略了数据源定义
  graphql:
    graphiql:
      enabled: true
      path: /graphiqls

至此,API 的实现已经完成。

接下来,将启动 API 应用程序并进行操作确认。

启动 GraphQL API 服务器并进行操作确认


要启动 API 应用程序,只需运行 Main.java。

可以使用 Maven 进行构建并运行 JAR 文件的方法,也可以使用 IDE 功能进行运行,具体方法随意选择。

此外,将使用 GraphiQL 作为 GraphQL 的客户端工具。

  • 端点:http://localhost:8080/graphql
  • 方法:POST

操作确认1


通过执行以下查询,成功获取了帐户信息。

代码语言:GraphQL
复制
query {
    accountById(accountId:"ACC01") {
        accountId,
        userName,
        age,
        accountType
}

操作确认2


接下来,将获取与帐户信息相关的各种信息。

通过执行以下查询,成功一次性获取了帐户信息及其关联的服务组、团队和团队关联的服务组信息。

代码语言:GraphQL
复制
query {
    accountById(accountId:"ACC01") {
        accountId,
        userName,
        age,
        accountType,
        serviceGroup {
            serviceGroupId
            serviceGroupName
        }
        team {
            teamId
            teamName
            teamAuthority
            serviceGroup {
                serviceGroupId
                serviceGroupName
            }
        }
    }
}

最后


这次介绍了简单查询示例的实现步骤,下一步可以尝试一些更高级的内容,如Mutation和分页。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 要实现的 API 的数据模型
  • 创建空白项目
  • 示例应用程序结构
  • 实现准备
    • 准备工作1:表定义和数据库连接定义设置
      • 准备工作2:日志设置
      • GraphQL API 实现
        • 步骤1:定义 GraphQL 模式
          • 步骤2:实现 DTO 类
            • 步骤3:实现 Repository 接口
              • 步骤4:实现 Controller 类
                • 步骤5:配置 GraphQL 端点 URL
                • 启动 GraphQL API 服务器并进行操作确认
                  • 操作确认1
                    • 操作确认2
                    • 最后
                    相关产品与服务
                    API 网关
                    腾讯云 API 网关(API Gateway)是腾讯云推出的一种 API 托管服务,能提供 API 的完整生命周期管理,包括创建、维护、发布、运行、下线等。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档