版本号 | 作者 | 版本号 | |
---|---|---|---|
v1.0.0 | 若布与宫合 | 8416837 | graphql-java 14.0 |
介绍
查看本人的【Python Graphql】教程及源码
查看Graphql入门教程_Nodejs版
用途
-
Get many resources in a single request
-
GraphQL 的部分吸引力在于,它可以帮助我们更好地处理那些昂贵的 HTTP/1 连接。这是因为 GraphQL 可以让客户端在一次请求回应中即可从获取来自多个服务的响应数据(服务聚合)。将此与以超媒体为中心的 API 进行比较,后者通常需要大量的网络请求(某些缓存可以提供帮助)
-
GraphQL 不仅为我们提供了减少往返请求或减少通过网络传输的字节数的功能
-
GraphQL 的功能以及最大的折衷之处就是它以客户为中心。在过去的几年中,这在很多人的心中是一个令人担忧的问题。丹尼尔·雅各布森(Daniel Jacobson)在5到7年前就其中一些问题写了许多惊人的文章。这是另一篇文章。
-
我们的 REST API 虽然非常有能力以通用方式处理来自我们设备的请求,但并未针对其中的任何一个进行过优化
-
GraphQL 通过帮助我们构建能够将客户端用例编译为服务器资源的服务器引擎,重新定义了客户端服务器边界。持久查询使这更容易理解,本质上是客户端生成的服务器资源
-
作为服务器端抽象的 GraphQL 在讨论它在HTTP/2世界中是否仍然有意义时要牢记。尽管维护各种用例可能会导致典型的基于终结点的 API 出现问题,但GraphQL 使 API 提供程序可以专注于公开更多的可能性,而无需考虑现有客户端的成本,也不必增加维护大量不同资源的复杂性。(它的确增加了成本:难以优化性能;并非总是可缓存的。这个经常需要在高度可定制的API中进行同样的权衡取舍)
-
基于API的查询语言
概念
查看概念
- TypeResolver提供了强大的功能,能够根据获取的数据转换为对应的Schema中定义的字段类型
查看schema定义 - 在GraphQL服务器,通过Runtime Wiring使GraphQL Schema运行,得到一个可执行的GraphQL Schema
实操
Demo
依赖
我的项目是Maven管理,因此引入:
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>14.0</version>
</dependency>
Java
这个Demo可以跑起来,我加了注释
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.StaticDataFetcher;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import static graphql.schema.idl.RuntimeWiring.newRuntimeWiring;
/**
* 功能:测试ql
*
* @author: cc
* @qq: 8416837
* @date: 2020/5/8 16:59
*/
public class HelloWorld {
public static void main(String[] args) {
// 定义数据结构
String schema = "type Query{hello: String}";
SchemaParser schemaParser = new SchemaParser();
TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema);
//赋值
RuntimeWiring runtimeWiring = newRuntimeWiring()
.type("Query", builder -> builder.dataFetcher("hello", new StaticDataFetcher("cc")))
.build();
//转成QL结构
SchemaGenerator schemaGenerator = new SchemaGenerator();
GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);
GraphQL build = GraphQL.newGraphQL(graphQLSchema).build();
// 执行查询
ExecutionResult executionResult = build.execute("{hello}");
System.out.println(executionResult.getData().toString());
}
}
进阶
查看官方文档
例子
准备
- 克隆代码
git clone https://github.com/graphql-java/tutorials
这是个Gradle项目 - 配置国内镜像库或私库
repositories {
maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
mavenCentral()
}
启动项目
默认端口8080
执行
- 地址
http://localhost:8080/graphql
使用工具调试
- 准备工具
# 克隆代码
git clone https://github.com/prisma-labs/graphql-playground
# 因为该项目使用yarn管理
npm install -g yarn --registry=https://registry.npm.taobao.org
# 查看yarn的镜像
yarn config get registry
yarn config set registry https://registry.npm.taobao.org -g
# 再次查看
yarn config get registry
# 注意 进入react包 一开始不小心在根目录执行过yarn
cd packages\graphql-playground-react
# yarn安装 经过一定时间的等待
yarn
安装中:
# 启动
yarn start
启动报错npm版本是 6.14.4报错:Error [ERR_STREAM_WRITE_AFTER_END]: write after end
- 改环境,使用Ubuntu安装,npm版本6.7.0,yarn版本1.13.0,安装成功:
报错:输入地址,出现了跨域错误,Playground分属不同内网ip,一个在宿主机,一个在虚拟机
Access to fetch at 'http://192.168.59.1:8080/graphql' from origin 'http://192.168.59.134:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
使用spring自带的web
因为前端报错,一时间没有解决,所以使用springBoot启动语法分析web
增加依赖:
implementation 'com.graphql-java-kickstart:graphiql-spring-boot-starter:5.0.4'
implementation 'com.graphql-java-kickstart:graphql-spring-boot-starter:5.0.4'
启动后,访问:http://localhost:8080/graphiql
效果图:
- 请求执行,简单过滤:
原理
在Java代码(获取)打断点,然后执行graphiql,请求执行断点:
参数传了进来,lambda表达式根据参数过滤出了对应的数据
启动初始化时,将数据关联(book与author关联):
初始化时,已经获取了数据源的数据;可以改成实时初始化,因为一般的需求场景是一开始不知道数据呀。
新增两个Query
执行,没响应:
当然没响应,因为没有注册这个接口:
注册步骤(就是打代码):
1)增加bookByName
return RuntimeWiring.newRuntimeWiring()
.type(newTypeWiring("Query")
.dataFetcher("bookByName", graphQLDataFetchers.getBookByNameDataFetcher()))
.type(newTypeWiring("Query")
.dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher()))
.type(newTypeWiring("Book")
.dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher()))
.build();
- 增加获取数据的逻辑
public DataFetcher getBookByNameDataFetcher() {
return dataFetchingEnvironment -> {
String name = dataFetchingEnvironment.getArgument("name");
return books
.stream()
.filter(book -> book.get("name").indexOf(name) >= 0)
.findFirst()
.orElse(null);
};
}
但是,这样写Query代码太冗余了,有没有优雅的写法呢?
以上截图中的代码模板一样。如果这样写,那就太不优雅了。后来认识到,ql只是schema,与业务逻辑无关。
语法
语法注意点
Schema
静态
type Records {
userId: String
username: String
name: String
gmtCreate: String
}
type GetData {
records: [Records]
}
[Records]加上方括弧,表示这是个数组。