HTML5技术

我的前端故事----我为什么用GraphQL - F-happy

字号+ 作者:H5之家 来源:H5之家 2017-09-06 09:04 我要评论( )

我的前端故事----我为什么用GraphQL 背景 今年我在做一个有关商户的app,这是一个包含商户从入网到审核、从驳回提交到入网维护的完整的生命周期线下推广人员使用的客户端软件,但故事并没有这么简单。。。 疑问 随着app的逐渐完善,遇到的问题也渐渐多了起来

我的前端故事----我为什么用GraphQL

背景

今年我在做一个有关商户的app,这是一个包含商户从入网到审核、从驳回提交到入网维护的完整的生命周期线下推广人员使用的客户端软件,但故事并没有这么简单。。。

疑问

随着app的逐渐完善,遇到的问题也渐渐多了起来,界面加载过久,初始化页面请求次数过多等各种各样的小毛病开始凸显了出来。于是我开始了优化之路,第一步便是从api请求入手,仔细查看了每个api返回的内容,一直奇怪为什么接口总是返回很多的数据回来,比如我需要一个商户的详细信息,可接口却会把这个商户相关的门店信息、所有人信息等其它各种各样的信息一起返回回来,如果是例如商户详情页面也就罢了,可是在商户列表这个接口下依旧返回如此之多的数据,可想而知这个列表有多大多复杂了。

后来问过后端的同学才知道是为了兼容 web 端的需求,一个接口需要同时为多个平台提供内容,这大大增加了接口的返回内容和处理逻辑,而且需求也经常改动,所以还不如把能用到的字段全都输出出来,免得每次改需求都要前后端一起联动。

反思

得知了结果,这确实是一个有“充分”理由的处理结果,可是真的只能这样了嘛?有没有什么更好的解决办法呢?我们先来总结一下现在遇到的问题:

以上三个问题看起来并不复杂,按照以往的逻辑其实也是很好解决的,就拿第一个来说,遇到多平台需要兼容时其实可以通过提供不同平台的接口来解决,例如这样:

:uid :uid :uid

又或者是通过不同的参数去控制:

:uid?platfrom=web

虽然这是一个方便的解决方案,但带来的其实是后端逻辑的增加,需要为不同平台维护不同的逻辑代码。

再说第二个问题,一个页面需要多次调用接口来聚合数据这块也可以通过多加接口的方式来解决:

或者是通过 http2 来复用请求,但这些方法不是增加工作量就是有兼容性问题,那么还有没有其他的方法呢?

如果大家还记得数据库的知识的话,就发现其实我们可以用 SQL 的思路去解决这些事情,那如果把后端抽象成一个数据库会怎么样呢?

我想要什么字段就 SELECT 什么字段就行咯,如果一个页面需要多个数据源的内容来填充那不就是组合 SQL 语句嘛。这样不就解决了上面提出的三个问题了嘛,而且无论前端需求如何变更,只要我们维持一个数据的超集,那么每次只要让前端改动查询语句就可以了,后端这里也不需要同步的去给某个接口增加字段什么的了,那么解决方案有了,那该怎么把后端抽象成一个数据库呢?

解决

既然思路有了,那么办法也会有的~这就是 Facebook 在2015年开源的 GraphQL

这又是一个什么东西呢?具体的介绍直接看它的官网就好了,我在这里就不多说了,直接来看看如何使用吧。

由于我的中间层是基于 Koa2 的,所以就在 koa2 上面做演示了,手写我们先安装依赖:

npm install graphql koa-graphql --save

这样我们就可以在 koa 中使用 graphql 了,然后就是配置路由了,按照文档上面的例子,我们可以这样写:

"use strict"; const router = require('koa-router')(); const graphqlHTTP = require('koa-graphql'); const GraphQLSchema = require('./graphql'); const renderGraphiQL = require('../utils/render_graphiQL'); const graphqlModule = graphqlHTTP((request) => ({ schema: GraphQLSchema, graphiql: false, context: {token: request.header.authorization, platform: request.query.platform}, formatError: error => ({ type: 'graphql', path: error.path, message: error.message, locations: error.locations ? error.locations[0] : null }) })); router.all('/graphql', graphqlModule);

我们来看看 graphqlModule 对象中都包含写什么吧,首先是 schema,这个是我们主要的解析逻辑,所有通过 graphql 的请求都会被传入这里进行解析和处理,graphiql 这个是 koa-graphql 自带的一个图形界面版的测试地址,后面我再单独介绍这个插件,context 是我们的上下文,如果我们需要在每个解析函数内获取到例如用户 token时就可以在这里赋值,需求说明的是这个必须是一个 object 对象,并且如果我们不指定的话会默认传整个 request 对象,接下来就是最后一个常用的属性了,formatError 是格式化错误的属性,我们可以根据业务的需求自定义我们的错误返回。

接下来去看看从最简单的 hello world 开始,然后完成一个最基础的 demo。

首先我们在客户端发起一个 post 请求,然后在请求 body 中带上我们的查询语句,在 Graphql 中有两种类型的查询,一直是 query 开头的查询操作,一种是 mutation 开头的修改操作。

query {hello}

这是一个最简单的查询,那么这个查询是如何通过解析的呢?上文说到全部的 Graphql 查询都会通过 schema 来进行解析,那我们看看上面定义的GraphQLSchema对象是个什么吧。

module.exports = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'rootQueryType', description: '查询操作', fields: { hello: { type: GraphQLString, description: '演示 demo', args: { name: {type: GraphQLString, description: '演示参数'} }, resolve(it, args, context) { return args.name; } } } }), mutation: new GraphQLObjectType({ name: 'rootMutationType', description: '新增或修改操作', fields: {} }) });

我们一步步来说,首先在这个文件中导出的是一个 GraphQLSchema 对象,这是 Graphql 的基础对象,里面包含了我们需要的两种类型,然后看 query 属性,它返回的是一个GraphQLObjectType对象,这是 Graphql 中对于 object 的基本类型,这个对象中包含 name:名称(全局唯一),description: 描述(这会自动的显示在文档中,虽然是非必须的,但是我还是强烈建议每个 Graphql 节点都写上,这样在后面的维护和查询中都非常有利),最后就是fields属性了,一个 Graphql 语句能查到什么就全靠这里写了什么了,在开始的例句中我们查询 query{hello},其实就是说我们要查根节点下的 hello 属性,所以这里我们就需要在 query 的 fields 中写上 hello 属性了,否则这条查询语句就无法生效了。

接下来我们看看这个 hello 属性中又包含了什么呢?首先我们需要指定它的类型,这很关键,这个类型是 hello 的返回类型,在这里我指定它返回的是一个字符串,除此之外还有 Int,Boolean 等 js 的基础类型可供选择,具体可去查看文档,当然了,在复杂情况下也可以返回 GraphQLObjectType 这种对象类型,然后就是对 hello 的描述字段description,接下来是args 属性,如果我们需要给这次查询传入参数的话就靠这个了,接下来就是最关键的 resolve 函数了,这个函数接受三个参数,第一个是上层的返回值,这在循环嵌套的情况下会经常使用,比如说如果 hello 还有子属性的话,那么子属性的这个参数就会是 args.name,第二个参数便是查询属性,第三个是我们一开始说的贯穿整个请求的上下文。下面是一个完整的例子:

Request: query{hello(name: "world")} Response: {"hello": "world"}

讲完了 query 操作,其实 mutation 操作也是类似的,我就不再展开说了。

总结

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 【前端笔记】 CSS 基础 - 专注精彩

    【前端笔记】 CSS 基础 - 专注精彩

    2017-09-04 14:01

  • 前端技术 - 铜镜123

    前端技术 - 铜镜123

    2017-08-29 13:01

  • 【javascript】函数中的this的四种绑定形式 — 大家准备好瓜子,我要讲故事啦~~ - 外婆的彭湖湾

    【javascript】函数中的this的四种绑定形式 — 大家准备好瓜子,我要

    2017-08-16 11:00

  • 前端用Datatables制作包含搜索、自动分页、按列排序、切换显示条数、打印以及多种文件格式保存等功能的Demo -

    前端用Datatables制作包含搜索、自动分页、按列排序、切换显示条数、

    2017-08-10 14:00

网友点评
!