本文已参与「新人创作礼」活动,一起开启掘金创作之路。
简介
官网定义 A query language for your api
背景
在后端微服务化的环境中,很多时候一个页面的数据,需要多个微服务的聚合才能得到,后端同学为了保持单一性通常会在多个restful接口中返回数据. restful API 存在以下问题:
-
接口数量众多,难以维护(往往一个组件,页面所需要的QUERY数据,需要调用几个api才能完成)
-
接口扩展成本高 增加字段 只会越来越臃肿
-
虽然有 API文档作为联调契约,但经常存在某种原因,后端需要修改参数和返回值,导致每一次的修改,前后端都会联动修改
-
后端经常作为微服务,不止一个消费方,有充分的理由拒绝 为本次的场景修改接口 虽然有controller作为中间处理环节,但后端可能不认
场景
场景一:
接口数量众多,难以维护
- /commercial 与/base /detail/${commercial} 三个接口共同构成了 客户详情页的数据源 但是里面有很多冗余以及重复数据,浪费带宽
- 前端在拆分组件的时候,往往根据页面布局接口来拆,可是接口的数据往往并非如此,一个组件的字段可能由多个接口的字段东平西凑出来的,那么接口调用的时机 可能就会发生变化 同时传递给组件的data就像这样
<CommercialInfo {...data1} {...data2} {...data3} />
<BaseInfo data={compose(data1,data2,data3)} />
鉴于以上问题,优化方案大致如下:
-
合并接口,去除冗余字段,由于部分接口不止一个消费方,该条不行
-
往往通过把公共状态往上提 来保证数据传递的统一性 这样的话,在页面mount的时候 就要同时请求至少三个接口,使用状态管理工具 也会面临同样的问题 这样的话会给代码增加一些心智负担 而且根本问题还是没有解决
graphql出现
基本概念
-
Schema 用来描述当前操作的结构模型
-
Query 获取数据,比如查找
-
Mutation 对数据作变更 例如 post put delete
-
resolver 对schema做解析的处理函数
简单的例子 helloworld
Query: {
hello: () => "Hello world!",
},
// 返回
{
"data": {
"hello": "Hello World"
}
}
复杂一点的例子
// 创建user
mutation createUser ($id: ID!, $name: String!, $email: String!, $age: Int,$gender:Gender) {
createUser(id: $id, name: $name, email: $email, age: $age,gender:$gender) {
id
name
age
email
gender
}
}
// 更新user
mutation UpdateUser ($id: ID!, $name: String!, $email: String!, $age: Int) {
updateUser(id: $id, name: $name, email: $email, age: $age) {
id
name
age
}
}
// 监听
subscription subsUser($id: ID!) {
subsUser(id: $id) {
id
name
age
email
}
}
使用graphql后 前后端的变化
- 后端不再产出restful api接口 将Controller层转换成了resolver
- 前端端联调不再依赖单个接口文档 共同约定一套Schema结构 前端根据Schema来定制自己的请求
困难
- graphql 对前端来说可以说是大大提高开发效率, 落地的话需要后端的全力配合
- 对 field 来说 每一条都会对数据库跑一query 对数据库有一定的性能影响 需要对数据库作优化