阅读 369

graphql,这次一定会!

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,只要提供的数据是请求方的母集,不论它们各自怎么变,都不需要因为对方牵一发而动全身。

🚀语法速览

操作类型

  1. query 查询:获取数据(参数)
  2. mutation 变更:对数据进行操作(增删改)
  3. substription 订阅:当数据发生更改,进行消息推送 \

query类型(response)

  1. 对象类型:用户在 schema 中定义的 type
type Obj{
  name:String,
  account:String,
  age:Int,
  salary(city:String):String
}//Obj为定义类型
复制代码
  1. 标量类型:
    a. String UTF‐8 字符序列。
    b. Int 有符号 32 位整数。
    c. Float 有符号双精度浮点值。
    d. Boolean true 或者 false。
    e. ID ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型。
    f. 也可以自己定义如下:
scalar Date
复制代码
  1. 枚举类型:
    a. 验证这个类型的任何参数是可选值的的某一个
    b. 与类型系统沟通,一个字段总是一个有限值集合的其中一个值。
enum Gender {
    MAN
    WOMAN
}
复制代码
  1. 接口类型:
    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 查询错误

  1. 特征:返回码为200,返回体 data 字段为 null ,返回体对象中有一个 errors 字段
  2. 例子: query document 语法错误错误

HTTP 错误

  1. 特征:返回码为 4XX 或 5XX ,返回体有 message 和 documentation_url 两个字段
  2. 例子:请求体 JSON 解析错误; access token 失效等

网络异常

  1. 特征: fetch 方法抛出异常
  2. 例子:手机无网络信号

JSON 解析异常

  1. 特征: Response.json() 方法抛出异常
  2. 例子:由于 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)

复制代码