我是靠谱客的博主 粗心石头,这篇文章主要介绍基于java的Graphql学习笔记Graphql 简介Graphql 核心概念,现在分享给大家,希望可以做个参考。

最近有需要使用Graphql +SpringBoot 实现一个BFF 服务,因此对Graphql 进行了学习和整合SpringBoot进行使用,简单写个笔记记录下学习心得(差不多是官网的内容,只是笔者是学习java的,所有借用java方便理解graphql概念,在这里简单记录下,整合SpringBoot原理和使用心得有空再整理一篇)

Graphql 简介

官网的定义是:GraphQL 用于API的查询语言,是通过使用为数据定义的类型系统执行查询的服务器端运行时。GraphQL不绑定任何特定的数据库或存储引擎,而是由您现有的代码和数据支持

个人理解(个人学习是基于java 和SpringBoot的基础上进行学习使用的感悟):
Graphql 是一种协议,可以使前端的查询精确到字段级别,不在是http的接口级别,数据由前端决定返回什么数据,使得接口不再传输冗余字段(前端用不到的字段),其他的写不出来了。

个人理解浅薄,也结合了SpringBoot进行整合使用,使用过程中并未真正理解其优势,可能是学习不够深入,如果读者有其他更深的感悟,也请不吝指导一二

Graphql 核心概念

Fields

​ 字段 ,可以是一个字符串类型(String),也可以是一个对象类型(Object)(同java中的字段)

Arguments

​ 每一个字段和嵌套对象都能有自己的一组参数,从而使得 GraphQL 可以替代多次 API 获取请求。甚至你也可以给 标量(scalar)字段传递参数(例如java中提供了获取标量的有参get方法)

Schema 和类型

Type System

​ 每一个 GraphQL 服务都会定义一套类型,用以描述你可能从那个服务查询到的数据。每当查询到来,服务器就会根据 schema 验证并执行查询.

​ GraphQL 查询语言本质就是在选择对象上的字段, 会有一个特殊的对象 “root” 开始,基于该对象上面进行字段选择

Object Types and Fields

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
type Character { name: String! appearsIn: [Episode!]! } 类比java : class Character { @NotNull String name; @NoEmpty List<Episode> appearsIn; }

Scalar Types

​ 标量类型,(类同Java中的基础数据类型,已经是最小的类型,没有属性),一个对象类型有自己的名字和字段,而某些时候,这些字段必然会解析到具体数据。这就是标量类型的来源:它们表示对应 GraphQL 查询的叶子节点

默认Scalar Types

Int:有符号 32 位整数。

Float:有符号双精度浮点值。

String:UTF‐8 字符序列。

Booleantrue 或者 false

ID:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型(如果定义了类型为ID,在返回的数据中存在从重复ID的数据,则会直接异常)

Enumeration Types

​ 枚举类型是一种特殊的Scalar Type(可以当成Java中枚举类的无属性简化版)

复制代码
1
2
3
4
5
enum FundType { CURRENCY LOF }

Lists and Non-Null

Lists 列表,同Java中的集合
Non-Null,用于检查数据入参,或者返回值是否为空

用于返回值上面:

复制代码
1
2
3
4
5
type Character { name: String! appearsIn: [Episode]! }

用于定义字段上的参数:

复制代码
1
2
3
4
5
6
query DroidById($id: ID!) { droid(id: $id) { name } }

Interfaces

​ 一个接口是一个抽象类型,它包含某些字段,而对象类型必须包含这些字段,才能算实现了这个接口(类似Java中的父类,但是graphql “子类” 必须全部定义“父类中的字段”)

复制代码
1
2
3
4
5
6
7
interface Character { id: ID! name: String! friends: [Character] appearsIn: [Episode]! }
复制代码
1
2
3
4
5
6
7
8
type Droid implements Character { id: ID! name: String! friends: [Character] appearsIn: [Episode]! primaryFunction: String }

Inline Fragments

如果要查询一个只存在于特定对象类型上的字段,你需要使用Inline Fragments,格式:... on Type
(有点像java中的多态,但是java多态为程序执行过程自动处理,而graphql需要通过… on Type 制定实际对象的类型和字段)
如:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
products(productType:null){ code name ... on Fund { fundType manager (code:"test"){ id name } } ... on Portfolio{ funds{ code name fundType manager (code:"test"){ id desc } } } }

Union Types

Union Types和接口十分相似,区别在于Union的类型之间不一定存在“继承”关系,类型之间的字段无需有共同字段等联系(目前没发现在java中可起到什么比较有意义的作用)

复制代码
1
2
3
4
5
union SearchResult = Manager | Fund type Query{ search(type:String): SearchResult # Union Types }
复制代码
1
2
3
4
5
6
7
8
9
search(type:"rf"){ __typename # 获取Fund类型名,用于在客户端区分不同的数据类型 ... on Fund{ code name } }

Input Types

传递复杂作为新建对象

复制代码
1
2
3
4
5
6
7
8
type Mutation{ createFund(input: FundInput!): String! } input FundInput { code: ID! name: String! }

verify

通过使用类型系统,你可以预判一个查询是否有效。这让服务器和客户端可以在无效查询创建时就有效地通知开发者,而不用依赖运行时检查

  1. 通过使用类型系统,你可以预判一个查询是否有效。这让服务器和客户端可以在无效查询创建时就有效地通知开发者,而不用依赖运行时检查
  2. 查询字段的时候,我们只能查询给定类型上的字段
  3. 查询一个字段时,如果其返回值不是标量或者枚举型,那我们就需要指明想要从这个字段中获取的数据
  4. 类似地,如果一个字段是标量,进一步查询它上面的字段也没有意义

execute

一个 GraphQL 查询在被验证后,GraphQL 服务器会将之执行,并返回与请求的结构相对应的结果,该结果通常会是 JSON 的格式

Query And Mutation Type

每一个 GraphQL 服务都有一个 query 类型,可能有一个 mutation 类型。这两个类型和常规对象类型无差,但是它们之所以特殊,是因为它们定义了每一个 GraphQL 查询的入口。因此如果你看到一个像这样的查询:

复制代码
1
2
3
4
5
type Query { hero(episode: Episode): Character droid(id: ID!): Droid }

自定义Scalar Types

复制代码
1
2
scalar Date

Aliases

复制代码
1
2
3
4
5
6
7
8
9
{ empireHero: hero(episode: EMPIRE) { name } jediHero: hero(episode: JEDI) { name } }

Fragments

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fragment fundsFields on Fund{ code name fundType manager (code:"test"){ id desc } } { funds { ... fundsFields } }

Inline Fragments

如果你查询的字段返回的是接口或者联合类型,那么你可能需要使用Inline Fragments来取出下层具体类型的数据

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
products(productType:null){ code name __typename ... on Fund { fundType manager (code:"test"){ id name } } ... on Portfolio{ funds{ code name fundType manager (code:"test"){ id desc } } } }

Operation name

操作类型:query*、*mutation 、subscription

操作名称是你的操作的有意义和明确的名称

Variables

一级方法将动态值提取到查询之外,然后作为分离的字典传进去。这些动态值即称为变量

使用变量:

  1. 使用 $variableName 替代查询中的静态值。
  2. 声明 $variableName 为查询接受的变量之一。
  3. variableName: value 通过传输专用(通常是 JSON)的分离的变量字典中

Variable definitions

复制代码
1
2
$episode: Episode

Default variables

复制代码
1
2
$episode: Episode = "JEDI"

Directives

变量动态地改变我们查询的结构,比如详情比普通概要显示更多字段,则可以通过指令动态调整获取的字段、结构

复制代码
1
2
3
@include(if: Boolean) 仅在参数为 true 时,包含此字段。 @skip(if: Boolean) 如果参数为 true,跳过此字段

服务端实现也可以定义新的指令来添加新的特性。 TODO ?

Mutations

查询字段时,是并行执行,而变更字段时,是线性执行,一个接着一个

Meta fields

__typename,一个元字段,以获得那个位置的对象类型名称,常配合Inline Fragments一起使用

内省

GraphQL 通过内省系统可以知道 GraphQL Schema 它支持哪些查询

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
query querySchema{ __schema{ types{ name } } Fund:__type(name: "Fund") { name kind fields{ name type{ name kind } } } ProductType: __type(name: "ProductType") { name kind } }

中文官网:https://graphql.cn/

最后

以上就是粗心石头最近收集整理的关于基于java的Graphql学习笔记Graphql 简介Graphql 核心概念的全部内容,更多相关基于java的Graphql学习笔记Graphql内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(80)

评论列表共有 0 条评论

立即
投稿
返回
顶部