概述
最近有需要使用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
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 字符序列。
Boolean
:true
或者false
。
ID
:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型(如果定义了类型为ID,在返回的数据中存在从重复ID的数据,则会直接异常)
Enumeration Types
枚举类型是一种特殊的Scalar Type(可以当成Java中枚举类的无属性简化版)
enum FundType {
CURRENCY
LOF
}
Lists and Non-Null
Lists 列表,同Java中的集合
Non-Null,用于检查数据入参,或者返回值是否为空
用于返回值上面:
type Character {
name: String!
appearsIn: [Episode]!
}
用于定义字段上的参数:
query DroidById($id: ID!) {
droid(id: $id) {
name
}
}
Interfaces
一个接口是一个抽象类型,它包含某些字段,而对象类型必须包含这些字段,才能算实现了这个接口(类似Java中的父类,但是graphql “子类” 必须全部定义“父类中的字段”)
interface Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
}
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 制定实际对象的类型和字段)
如:
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中可起到什么比较有意义的作用)
如
union SearchResult = Manager | Fund
type Query{
search(type:String): SearchResult # Union Types
}
search(type:"rf"){
__typename # 获取Fund类型名,用于在客户端区分不同的数据类型
... on Fund{
code
name
}
}
Input Types
传递复杂作为新建对象
type Mutation{
createFund(input: FundInput!): String!
}
input FundInput {
code: ID!
name: String!
}
verify
通过使用类型系统,你可以预判一个查询是否有效。这让服务器和客户端可以在无效查询创建时就有效地通知开发者,而不用依赖运行时检查
- 通过使用类型系统,你可以预判一个查询是否有效。这让服务器和客户端可以在无效查询创建时就有效地通知开发者,而不用依赖运行时检查
- 查询字段的时候,我们只能查询给定类型上的字段
- 查询一个字段时,如果其返回值不是标量或者枚举型,那我们就需要指明想要从这个字段中获取的数据
- 类似地,如果一个字段是标量,进一步查询它上面的字段也没有意义
execute
一个 GraphQL 查询在被验证后,GraphQL 服务器会将之执行,并返回与请求的结构相对应的结果,该结果通常会是 JSON 的格式
Query And Mutation Type
每一个 GraphQL 服务都有一个 query
类型,可能有一个 mutation
类型。这两个类型和常规对象类型无差,但是它们之所以特殊,是因为它们定义了每一个 GraphQL 查询的入口。因此如果你看到一个像这样的查询:
type Query {
hero(episode: Episode): Character
droid(id: ID!): Droid
}
自定义Scalar Types
scalar Date
Aliases
{
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
}
Fragments
fragment fundsFields on Fund{
code
name
fundType
manager (code:"test"){
id
desc
}
}
{
funds {
... fundsFields
}
}
Inline Fragments
如果你查询的字段返回的是接口或者联合类型,那么你可能需要使用Inline Fragments来取出下层具体类型的数据
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
一级方法将动态值提取到查询之外,然后作为分离的字典传进去。这些动态值即称为变量。
使用变量:
- 使用
$variableName
替代查询中的静态值。 - 声明
$variableName
为查询接受的变量之一。 - 将
variableName: value
通过传输专用(通常是 JSON)的分离的变量字典中
Variable definitions
$episode: Episode
Default variables
$episode: Episode = "JEDI"
Directives
变量动态地改变我们查询的结构,比如详情比普通概要显示更多字段,则可以通过指令动态调整获取的字段、结构
@include(if: Boolean) 仅在参数为 true 时,包含此字段。
@skip(if: Boolean) 如果参数为 true,跳过此字段
服务端实现也可以定义新的指令来添加新的特性。 TODO ?
Mutations
查询字段时,是并行执行,而变更字段时,是线性执行,一个接着一个
Meta fields
__typename,一个元字段,以获得那个位置的对象类型名称,常配合Inline Fragments一起使用
内省
GraphQL 通过内省系统可以知道 GraphQL Schema 它支持哪些查询
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 简介Graphql 核心概念所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复