如何使用 Spring Boot 在 Java 中构建 GraphQL 服务
注意:请注意,本文内容现已过时,因为自 2019 年我撰写本文以来,技术已经发生了变化。
我们先快速了解一下所涉及的技术。
GraphQL
与 REST 相比,GraphQL 算是后起之秀,但我认为它的改进如此之大,以至于我打算把所有新写的 API 都迁移到它上面。我见过太多 API 返回海量数据,而用户真正需要的只是一组标识符,然后通过循环遍历这些标识符,再从第二个端点查询与这些标识符相关的其他数据,这就凸显了第二个问题。光是想想就觉得不可思议,我只想调用一次 API,就能获取所有我需要的信息。
我不会详细解释为什么 GraphQL 更好,网上有很多文章可以让你自行判断。我只想说,我决定切换到 GraphQL 的主要原因有两个:一是能够轻松地在请求中包含你想要接收的数据结构;二是能够将原本需要多个 REST 请求才能完成的任务合并成一个 GraphQL 查询。这两点都比 REST 有了巨大的改进。当然,你也可以尝试用这种方式编写 REST 端点,但那样它们就不再是 REST 了,而 GraphQL 的设计初衷就是如此。
好了,现在我们已经解决了这个问题,让我们开始编写代码吧。我们将使用Spring Boot在 Java 中构建一个简单的 GraphQL API。
Spring Boot
我之前主要用 PHP 开发,最近才发现 Spring 框架,尤其是 Spring Boot 的妙用。它让搭建新项目变得极其简单;它对如何配置和构建许多传统的样板代码(例如控制器、数据访问等)有着自己独特的见解,但当你想按照自己的方式配置时,它又会完全放手。在这个例子中,我们不需要编写任何控制器;只需要实体模型、类型和 GraphQL schema 即可。
先决条件
本项目将使用 Java 8。我尝试过 Java 10 和 9,但由于 Lombok 依赖项存在问题,本教程暂时只能使用 Java 8。问题修复后,我会更新到 Java 10。我们将使用 Spring Boot 2,它基于 Spring Framework 5,并已为您完成所有设置。为了简化操作,我们还将使用 Maven 构建框架来管理 Java 依赖项。此外,我们还将使用优秀的 GraphQL-Java 库 Spring Boot Starter 来获取 GraphQL 和 GraphIQL 端点(稍后会详细介绍)。最后,我添加了 Project Lombok,它允许您对类、方法、变量等进行注解,从而提供样板功能。
以下是我将要使用的具体版本:
- Java 8 (1.8.0_172)
- Spring Boot 2.0.2
- GraphQL-Java Spring Boot Starter 4.0.0
- Maven 3.5.2
- 龙目岛项目 1.16.20
我们走吧!
首先,创建一个新文件夹,然后在你选择的集成开发环境(IDE)中打开它。我用的是Microsoft Visual Studio Code。它真的是目前最好的免费代码编辑器,抱歉了,Atom。
创建一个名为 pom.xml 的新文件,并将以下内容放入其中:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>uk.co.benskin</groupId>
<artifactId>graphql_spring_boot_tutorial</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>graphql_spring_boot_tutorial</name>
<description>Learn how to build a graphql spring boot based java service</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphiql-spring-boot-starter</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>
</project>
上述文件前半部分定义了我们的项目,请将项目名称、描述等内容替换为您自己的项目详细信息。后半部分定义了六个依赖项:
- Spring Boot Web - 提供通过 Web 协议支持我们端点的功能
- Spring Boot DevTools——对开发、构建和调试非常有用
- GraphQL-Java 工具 - 加载并支持我们的 GraphQL schema
- GraphQL-Java Spring Boot Starter for GraphQL - 在我们的 Spring 上下文的 /graphql 端点托管我们的模式
- GraphQL-Java Spring Boot Starter for GraphIQL - 一个基于 Web 的 UI,用于与 /graphql 端点交互,并了解该端点的模式。
- Project Lombok 用于减少 Java 代码中的样板代码
请继续安装所有依赖项。
mvn install
首次安装依赖项后,会输出一大堆信息,之后您应该会看到一条消息,内容为“构建成功”。
好了,现在我们已经准备好开始所需的一切了。
创建一个文件夹
src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/
在其中创建一个文件
GraphQLSpringBootTutorialApplication.java
请放入以下内容
package uk.co.benskin.graphql_spring_boot_tutorial;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GraphQLSpringBootTutorialApplication {
public static void main(String[] args) {
SpringApplication.run(GraphQLSpringBootTutorialApplication.class, args);
}
}
这将加载一个新的 Spring 应用程序上下文,并自动将其与我们的 GraphQL-Java 启动器依赖项集成。
现在让我们尝试启动应用程序,看看会得到什么结果。
mvn spring-boot:run
你应该会看到很多信息输出,希望其中还有几行文字说明。
INFO 64612 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
INFO 64612 --- [ restartedMain] b.g.GraphQLSpringBootTutorialApplication : Started GraphQLSpringBootTutorialApplication in 4.886 seconds (JVM
现在打开浏览器,访问http://localhost:8080
您应该会看到类似这样的错误页面。
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
[DATE]
There was an unexpected error (type=Not Found, status=404).
No message available
很好!服务器正在运行,但我们还没有告诉它如何响应根目录“/”的请求,所以现在尝试访问http://localhost:8080/graphiql,你应该会看到一个漂亮的界面,用于与你的(尚未构建的)端点进行交互。
构建 GraphQL Schema
现在到了有趣的部分,GraphQL schema。我不会详细介绍 GraphQL 的工作原理,请参考 GraphQL 教程。
创建此文件
src/main/resources/petshop.graphqls
然后将以下内容填入
type Query {
pets: [Pet]
}
type Pet {
id: Int
type: Animal
name: String
age: Int
}
enum Animal {
DOG
CAT
BADGER
MAMMOTH
}
上面我们定义了主查询,它将返回一个名为“pets”的宠物类型数组。宠物的类型是一个枚举类型,其定义如下,枚举类型为Animal。
构建 API
现在回到 Java 代码部分。我们将创建几个文件夹来帮助我们组织代码。文件夹的名称和位置没有限制,但我强烈建议您使用子文件夹来更好地组织代码,无数未来的开发者都会感谢您的。
创建此文件夹
src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/enums
创建此文件
src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/enums/Animal.java
以下是内容
package uk.co.benskin.graphql_spring_boot_tutorial.enums;
public enum Animal {
DOG,
CAT,
BADGER,
MAMMOTH
}
枚举类型定义完毕,现在来看宠物实体模型。
创建此文件夹
src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/entities
创建此文件
src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/entities/Pet.java
以下是内容
package uk.co.benskin.graphql_spring_boot_tutorial.entities;
import lombok.Data;
import uk.co.benskin.graphql_spring_boot_tutorial.enums.Animal;
@Data
public class Pet {
private long id;
private String name;
private Animal type;
private int age;
}
这是一个简单的 POJO,使用 @Data 注解来处理样板式的 getter、setter 和构造函数。
现在创建 GraphQL 解析器的目录
src/main/java/uk/co/benskin/graphql-spring-boot-tutorial/resolvers
并创建文件
src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/resolvers/Query.java
然后把它填满这个
package uk.co.benskin.graphql_spring_boot_tutorial.resolvers;
import java.util.ArrayList;
import java.util.List;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import org.springframework.stereotype.Component;
import uk.co.benskin.graphql_spring_boot_tutorial.entities.Pet;
import uk.co.benskin.graphql_spring_boot_tutorial.enums.Animal;
@Component
public class Query implements GraphQLQueryResolver {
public List<Pet> pets() {
List<Pet> pets = new ArrayList<>();
Pet aPet = new Pet();
aPet.setId(1l);
aPet.setName("Bill");
aPet.setAge(9);
aPet.setType(Animal.MAMMOTH);
pets.add(aPet);
return pets;
}
}
好了,这就是调用 GraphQL 端点获取宠物列表(本例中为一只宠物)所需的一切信息。
停止 Maven(Ctrl/Cmd + C)然后使用 `mvn spring-boot:run` 重新启动构建。
要查看运行效果,请访问http://localhost:8080/graphiql,您将看到一个友好的用户界面供您体验。同样,我不会详细介绍如何使用 GraphIQL 界面。
在 GraphIQL 标题正下方、历史记录框右侧的框中,您可以输入请求。请将以下内容复制并粘贴到此处:
{
pets {
name
age
type
}
}
然后点击播放图标(位于 GraphIQL 标题旁边)。您应该会看到类似如下的响应:
{
"data": {
"pets": [
{
"name": "Bill",
"age": 9,
"type": "MAMMOTH"
}
]
}
}
恭喜!您刚刚用 Java 和 SpringBoot 编写了一个 GraphQL 服务。好的,它目前只会返回一条记录,所以在第二部分中,我们将介绍如何通过Spring Data项目访问数据库,该项目利用了 Java 持久化 API (JPA)。
非常感谢您阅读这篇文章!如果您喜欢这篇文章,请留言告诉我您的想法,或者提出任何改进建议;也别忘了点击下方的爱心/独角兽/收藏按钮,您的支持对我意义重大 :)
文章来源:https://dev.to/sambanskin/howto-build-graphql-services-in-java-with-spring-boot---part-1-38b2