1. 概述
GraphQL 是由 Facebook 开发的查询语言,旨在构建基于直观灵活语法的客户端应用,用于描述数据需求和交互。
传统 REST 调用存在两大痛点:
- ❌ 客户端无法请求定制化数据(要么全拿,要么全不要)
- ❌ 随着平台增长,需要维护大量接口,客户端常需跨多个接口请求数据
GraphQL 通过单一 URL 解决这些问题:客户端只需发送描述需求的查询字符串,即可获取精确数据。
2. GraphQL 核心术语
2.1 基础概念
术语 | 说明 |
---|---|
Query | 只读操作,类似 REST 的 GET |
Mutation | 读写操作,类似 REST 的 POST/PUT/DELETE |
Resolver | 解析器,连接操作与后端处理逻辑(类比 REST 的 MVC 控制器) |
Type | 定义响应数据结构,可包含关联其他 Type 的字段 |
Input | 定义输入数据结构,类似 Type 但用于请求 |
Scalar | 基础类型(String/Int/Boolean/Float 等) |
Interface | 接口,定义字段规范供其他对象继承 |
Schema | 模式,管理所有可执行的查询和变更 |
2.2 模式加载方式
GraphQL 支持两种模式定义方式:
接口定义语言(IDL)
简洁直观,官方推荐语法:type User { firstName: String }
编程语言定义
以 Java 为例:GraphQLObjectType userType = newObject() .name("User") .field(newFieldDefinition() .name("firstName") .type(GraphQLString)) .build();
3. 接口定义语言详解
IDL(也称 SDL)是定义 GraphQL 模式的最简洁方式,语法规范已纳入官方标准。
用户/邮箱系统示例:
schema {
query: QueryType
}
enum Gender {
MALE
FEMALE
}
type User {
id: String!
firstName: String!
lastName: String!
createdAt: DateTime!
age: Int! @default(value: 0)
gender: [Gender]!
emails: [Email!]! @relation(name: "Emails")
}
type Email {
id: String!
email: String!
default: Int! @default(value: 0)
user: User @relation(name: "Emails")
}
⚠️ 注意:!
表示非空字段,@relation
定义关联关系
4. GraphQL-java 实践
4.1 核心特性
- 基于 GraphQL 规范 的 Java 实现
- 要求 Java 8+ 环境
- 支持 注解驱动 开发(避免冗余 IDL 代码)
4.2 依赖配置
Maven 依赖:
<!-- GraphQL 注解支持 -->
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-annotations</artifactId>
<version>3.0.3</version>
</dependency>
<!-- HTTP 服务框架(示例用 Ratpack) -->
<dependency>
<groupId>io.ratpack</groupId>
<artifactId>ratpack-core</artifactId>
<version>1.4.6</version>
</dependency>
💡 提示:也可替换为 Vert.x/Spark/Spring Boot 等框架
4.3 完整实现案例
4.3.1 定义数据模型
@GraphQLName("user")
public class User {
@GraphQLField
private Long id;
@GraphQLField
private String name;
@GraphQLField
private String email;
// 省略 getter/setter/构造方法
}
4.3.2 请求处理器
@Override
public void handle(Context context) throws Exception {
context.parse(Map.class)
.then(payload -> {
Map<String, Object> parameters = (Map<String, Object>)
payload.get("parameters");
ExecutionResult executionResult = graphql
.execute(payload.get(SchemaUtils.QUERY)
.toString(), null, this, parameters);
Map<String, Object> result = new LinkedHashMap<>();
if (executionResult.getErrors().isEmpty()) {
result.put(SchemaUtils.DATA, executionResult.getData());
} else {
result.put(SchemaUtils.ERRORS, executionResult.getErrors());
LOGGER.warning("Errors: " + executionResult.getErrors());
}
context.render(json(result));
});
}
4.3.3 查询操作
@GraphQLName("query")
public class UserQuery {
@GraphQLField
public static User retrieveUser(
DataFetchingEnvironment env,
@NotNull @GraphQLName("id") String id) {
// 返回用户逻辑
}
@GraphQLField
public static List<User> listUsers(DataFetchingEnvironment env) {
// 返回用户列表逻辑
}
}
4.3.4 变更操作
@GraphQLName("mutation")
public class UserMutation {
@GraphQLField
public static User createUser(
DataFetchingEnvironment env,
@NotNull @GraphQLName("name") String name,
@NotNull @GraphQLName("email") String email) {
// 创建用户逻辑
}
}
4.4 请求与响应示例
创建用户
请求:
{
"query": "mutation($name: String! $email: String!){
createUser (name: $name email: $email) { id name email age } }",
"parameters": {
"name": "John",
"email": "john.doe@example.com"
}
}
响应:
{
"data": {
"createUser": {
"id": 1,
"name": "John",
"email": "john.doe@example.com"
}
}
}
查询用户(定制字段)
请求:
{
"query": "query($id: String!){ retrieveUser (id: $id) {email} }",
"parameters": {
"id": 1
}
}
响应:
{
"data": {
"retrieveUser": {
"email": "john.doe@example.com"
}
}
}
✅ 关键优势:客户端可精确控制返回字段,避免冗余数据传输
5. 总结
GraphQL 作为 REST 的替代方案,显著简化了客户端/服务端交互复杂度:
- 单一接口解决数据获取问题
- 客户端按需获取数据
- 强类型模式保障数据一致性
完整示例代码见 GitHub 仓库