graphql是什么
刚开始看到graphql多多少少会有种,啊这...这!什!么!🙉
但是一旦接受了他的设定就感觉他跟ts还是有点像的。
废话不多说,马上开搞!
官网解释:
GraphQL 是一个用于 API的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。一个 GraphQL 服务是通过定义类型和类型上的字段来创建的,然后给每个类型上的每个字段提供解析函数。
简单点:
ask exactly what you want.要啥给啥,对res,req进行一定的格式化
为什么使用graphql👏
传统restful
- 数据冗余,请求过多
- 若我们想获得某个用户的信息,最初可能只有id、昵称,但随着需求的变化,用户所包含的字段可能会越来越多,年龄、性别、头像、经验、等级,等等。GET用户信息的接口,我们就算只是想要一个用户的一两条信息,通过该API,我们也会得到他的整个信息。
- 若我们想获得一个用户列表,实际需要调用多个独立的API才能获取到足够的数据,或者是另外一个接口,给后端增加麻烦
- restful改动接口麻烦
- restful中一旦要改动API,不管是增删值域,改变值域范围,还是增减API数量,改变API url,都很容易变成伤筋动骨的行为,双方均需要改变
graphql好处
- 减少数据和请求冗余
- schema格式化
- 通过定义schema限制了res,req的格式和类型
- 接口校验
- 同上所示,不需要其他工具来验证query
- 接口变动,维护与文档
- client只用说明想要的数据,不需要具体格式。server,只要提供的数据是请求方的母集,不论它们各自怎么变,都不需要因为对方牵一发而动全身。
🚀语法速览
操作类型
query 查询:获取数据(参数)mutation 变更:对数据进行操作(增删改)substription 订阅:当数据发生更改,进行消息推送 \
query类型(response)
- 对象类型:用户在 schema 中定义的 type
type Obj{
name:String,
account:String,
age:Int,
salary(city:String):String
}//Obj为定义类型
- 标量类型:
a.StringUTF‐8 字符序列。
b.Int有符号 32 位整数。
c.Float有符号双精度浮点值。
d.Booleantrue 或者 false。
e.IDID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型。
f. 也可以自己定义如下:
scalar Date
- 枚举类型:
a. 验证这个类型的任何参数是可选值的的某一个
b. 与类型系统沟通,一个字段总是一个有限值集合的其中一个值。
enum Gender {
MAN
WOMAN
}
- 接口类型:
a. 一个接口是一个抽象类型,它包含某些字段,而对象类型必须包含这些字段,才能算实现了这个接口。
interface Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
}
//这意味着任何实现 Character 的类型都要具有这些字段,并有对应参数和返回类型。
b. 继承拓展性
type Human implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
starships: [Starship]
totalCredits: Int
}
type Droid implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
primaryFunction: String
}
输入类型(request)
input ReviewInput {
stars: Int!
commentary: String
}
异常处理
GraphQL 查询错误
- 特征:返回码为200,返回体 data 字段为 null ,返回体对象中有一个 errors 字段
- 例子: query document 语法错误错误
HTTP 错误
- 特征:返回码为 4XX 或 5XX ,返回体有 message 和 documentation_url 两个字段
- 例子:请求体 JSON 解析错误; access token 失效等
网络异常
- 特征: fetch 方法抛出异常
- 例子:手机无网络信号
JSON 解析异常
- 特征: Response.json() 方法抛出异常
- 例子:由于 fetch 方法一旦开始接收到返回信息就会立刻 resolve , Response.json() 的解析过程就会开始,如果此时网络突然中断,未能接受到全部的返回体,则 Response.json() 的解析就会失败抛出异常
graphql劣势
- 每一个不同类型的请求都得写返回方案
- 查不到时 还是200 返回null
😈epxress+graphql小实践
const express = require('express')
const { buildSchema } = require('graphql')
const graphqlhttp = require('express-graphql')
//定义shema查询和类型
const schema = buildSchema(`
type Obj{
name:String,
account:String,
age:Int,
salary(city:String):String
}
type Query{
hello:String
age:Int
account:Obj
getName(class:Int!):[String]
getAccount(user:String):Obj
accounts:[Account]
}
input AccountInput{
name:String,
age:Int,
}
type Account{
name:String,
age:Int,
}
type Mutation{
createAccount(input:AccountInput):Account
updateAccount(id:String,input:AccountInput):Account
}
`)
const db = {}
//定义查询对应处理器
const root = {
accounts: () => {
let arr = []
for (let i in db) {
arr.push(db[i])
}
return arr
},
hello: () => {
return 'hello world'
},
age: () => {
return 123
},
createAccount({ input }) {
db[input.name] = input
return db[input.name]
},
updateAccount({ id, input }) {
const obj = Object.assign({}, db[id], input)
db[id] = obj
return obj
},
getName({ class: classNo }) {
const obj = {
11: ['gsc11', 'gsc22', 'gsc33'],
22: ['gsc2', 'gsc44', 'gsc66']
}
return obj[classNo]
},
getAccount({ user }) {
const name = user;
const age = 22;
const account = '123';
const salary = ({ city }) => {
if (city == 'bj' || city == 'sh' || city == 'gz') {
return '10k'
}
return '6k'
}
return {
name,
age,
account,
salary
}
},
account: () => {
return {
name: 'gsc',
account: '123',
age: '18s'
}
}
}
const app = express()
app.use('/graphql', graphqlhttp({
schema: schema,
rootValue: root,
graphiql: true
}))//公开文件夹供访问
app.use(express.static('public'))
app.listen(3000)