All Articles

GraphQL笔记

1. 前言

1.1 为什么GraphQL

REST作为前后端数据交互的业界标杆有其存在的合理性和必要性,但同时用过的人自然也很明白REST接口有其固有的问题存在,而且是很难通过设计和实现上的优化来进行规避。业界一直有各种声音想找到REST的替代者,直到这两年,终于在FB的引导下做出了GraphQL这个设计。GraphQL确实解决了不少REST接口中存在的问题。

本文的主要目的就是初探GraphQL的实现,制作简单的例子,寻找GraphQL和REST的异同,并尽可能找到GraphQL中存在的问题。

详细阅读:

1.2 资料列表

  • FB官方的GraphQL网站:学习第一站,必然先去这里取经
  • FB官方的GraphQLspecification:类似RFC的东西,详细的文字specification
  • Github上FB的GraphQL项目组:一些好用的工具和类库
  • GraphQL.js:FB官方的JS实现
  • Github官方的GraphQL API手册V4版本:有相当多值得借鉴的地方
  • Github上的Apollo GraphQL项目组:算是看到现在做的最好的GraphQL解决方案集合之一了
  • Github上的Graphcool项目组:设计思路很优秀的一个GraphQL解决方案,目前的进度较初步
  • Building URL shortener using React, Apollo and GraphQL — Part I:一篇蛮贴近使用者的教程,用的技术是apollo作为前端,graphcool作为后端,可以阅读理解下

1.3 选择

任何一个技术,在我观察下来值得进场进行学习的时间点上,肯定已经有至少一到两款成熟(半成熟)的解决方案可以选择使用了。即便只是一个很简单的学习案例,技术的选择仍旧需要谨慎。

就目前看来apollo和graphcool是比较重量级的两个选择,或者可以说是主流的选择。

就这两者的选择,我最后的理由很简单:

  • apollo是纯JS的实现,对纯JS技术堆栈的团队来说相对友好,出了问题可以自行解决,甚至可以反向贡献
  • graphcool的后端是Scala实现的,所有的其他语言的工具类库都只是桥接,一旦出了问题,就需要理解Scala语言的实现,甚至需要去找JVM中的问题,很不友好

后续的行文都会以Apollo解决方案为核心。(其实Apollo也就是一些插件,说到底真正使用的核心其实还是FB官方的graphql)

2. 技术点学习

其实这里的技术点最关键的还是本质的GraphQL的技术点,后面其他类似Apollo和Graphcool,无非也是在这个基础上再做封装和拓展。

2.1 GraphQL

  • 查询和变更:GraphQL(客户端)如何进行查询,查询语句的格式
  • Schema 和类型:GraphQL的类型系统,如何定义类型
  • 验证:GraphQL(服务器)如何对查询进行验证
  • 执行:GraphQL(服务器)如何处理查询请求,如何组织返回结构
  • 内省:如何在不明白服务器具体提供哪些查询功能的情况下使用GraphQL接口

基本上,官方的GraphQL教程只提供了最基础的GraphQL自身的一些点,要真正应用起来还缺了不少东西,e.g:

  • 如何批量化自动化地进行客户端请求:GraphQL的客户端请求不单单仅仅只是一个URL或者一个Post请求带几个参数,作为只有一个入口的API系统,所有的客户端请求都要以字符串的形式构建,对于客户端来说也是很大的工作量
  • 如何做好数据到接口的映射:最好能有数据模型到API接口的转换映射工具,如果按FB官方GraphQL简介中那样每一段代码都自己写,这个工作量还不如去写REST
  • 如何做好缓存工作:GraphQL的请求非常自由,在对外的API这一层到中间的业务层之间,如何添加缓存就成了设计上的一个大问题
  • 等等

2.2 Apollo

2.2.1 主要文档入口

2.2.2 客户端

  • apollo-client-preset:整合完成的客户端包
  • ApolloClient:客户端实例
  • ApolloLink:这部分有点不太能理解
    • Apollo Link is a simple yet powerful way to describe how you want to get the result of a GraphQL operation, and what you want to do with the results.
    • StatefulLink:有状态的Link可以看下,在实例内部保存了一些状态数据
  • 剩下的内容和React等实现联系得太过紧密,可以不用在高层抽象理解的时候即刻就去看,放后面也没问题
  • 从现在简单了解来看,Apollo的客户端其实并没有解决什么实际的问题,API仍旧需要自己组装一堆字符串去进行调用;Apollo提供的无非就是一些封装好的接口,本质仍旧是那套
  • 对GraphQL来说,相对服务器的复杂度,客户端的复杂度其实要低得多,问题仅在于如何高效地研发,减少编码量

2.2.3 服务器

  • End-to-End Example:Apollo官方的Example,基本上简单到极致了,和直接裸用GraphQL.js没有本质区别
  • POST and GET format:请求格式,就是GraphQL的基本格式,没有黑科技
  • 其他没什么有营养的东西了,服务器实在是简单,当然也意味着没有解决我之前提到的问题

2.2.4 工具集

GraphQL Tools is an npm package and an opinionated structure for how to build a GraphQL schema and resolvers in JavaScript, following the GraphQL-first development workflow.

简单来说就是一堆API,方便你制作Schema和Resolvers。但实际上并没有解决映射和代码量(研发工作量)的问题。

3. 范例 - Apollo

看下官方的End-to-End Example基本上就足够了。当然这里仅只有服务器端的代码,但鉴于GraphQL的复杂度基本上都集中在服务器端,这个例子也OK了。

4. 总结

4.1 结论

先说结论,就目前GraphQL的情况来看,仍旧不适合选为业务的主力技术选型投入生产。经过那么多年的发展,GraphQL的表现只能说不温不火。仔细看下FB的GraphQL的specification的话,其实内容也没多少,而FB的教程网站上,内容也就那么点。可以说GraphQL本身并不是一个很复杂的技术,就类似FB的另一个开源项目React,其中的理念”虚拟DOM”也是类似的量级设计,作为比较可以很清楚看到React的社区和现状应该说是非常繁荣的,爆炸式的发展。而相较之下GraphQL就很一般了。

关键的杀手级的产品到现在仍旧还看不见。我所知道的两款比较重要的产品:Apollo仅仅只能说是能用,它只是在GraphQL官方的基础上做了一些简化API的封装,仅此而已;而Graphcool,我只能说现在还处在一个早期阶段,无论是文档,还是范例,还是社区,都很初级,远没到能投入生产的地步。

所以目前来看,GraphQL仍旧只适合观望,而不是投入。

4.2 问题

那么GraphQL的问题是什么呢,就我的理解,主要在于复杂度的分配。

举例来说,如果一个项目的业务复杂度是5,技术复杂度(纯架构设计)是10。那么REST在项目初期整个复杂度只有1,随着项目的发展,业务的拓展,复杂度可能在后期急速上升。而GraphQL则相反,在项目初期,整体的复杂度就直接上到了可能8、9的位置,而后面则一直保持,即便业务在后期再怎么拓展,整体的复杂度都会稳定维持在这个水准线附近。

简单解释下一下,其实这很容易理解。

RESTful作为一项成熟的技术,在JS界就有诸如Swagger这样的神器工具,社区对它的支持非常完美。项目投产,基本上不需要考虑技术上的问题,直接做就是了。业务需要数据A,那我就做一个endpoint A,业务需要数据B,那我就做一个endpoint B。如果客户端需要混合数据A+B,且觉得两次HTTP请求Cost太大,那我就做个新的endpoint AB,把A+B的数据直接吐出去就好了。这样,根据需求来,要什么给什么,研发的效率会非常高。当然,RESTful的问题也是出在这里,当你的业务量级急速发展的时候,项目的后续维护管理会非常困难,那么多的endpoint哪些有用哪些没用没有任何人清楚,到后来数据模型一改可能需要改动的API不计其数。项目的维护成本呈指数级上升。

GraphQL则完全相反,其理念在于客户端endpoint只有一个,而这个终端可以根据查询条件来获取后端数据模型中的任何数据。在项目投产初期,及后续业务拓展的时候,研发的代码量会比较高,因为无论客户端需要不需要服务端都必须将模型解析出去(resolver),而且是解析到字段级别,层层下行直到目标成为标量。当然有人可能会说,没有人强制要求把所有的服务端模型都解析出去,但一旦在研发的过程中某些解析某些不解析,到后面会遇到和RESTful一样的问题:管理复杂度上升,所以最好的做法就是一开始都解析,访问权限则另说。所以在项目复杂度上,GraphQL是非常平稳的,只要有模型,我就要做映射要做解析,做完了,那么客户端想要什么和我就没关系了,反正都能拿得到,不存在API后期泛滥的问题。但解析和映射的代码量将非常可观,研发的成本可以想见是不会低的,而且初期的构建难度会高于RESTful,架构师必须把很多东西都想清楚才能开始。毕竟GraphQL是对于后端数据的图映射,在resolver里基本上是一一对应的关系,不方便做类似RESTful接口那样在逻辑层进行返回数据和模型之间的转换。

所以GraphQL的项目,难度在前面,好处在后面,对小型项目来说根本没有意义。小型项目当然会选技术和社区更成熟的RESTful解决方案。

4.3 设计理念

在我看来,GraphQL要真的爆发开来,还是必须要有一款杀手级应用做好工具和生态。由我设计的框架,比如最近用的很重的SASDN,设计理念很简单:为使用者减负,使用者只需要编写数据模型的定义,然后框架会自动将大量代码生成出来,使用者只需要专注在需要他们编写的业务代码上即可。

Graphcool目前是在这个道路上走,但离终点仍旧非常遥远。需要解决的问题有很多:Scala的服务器、初级的项目进度、文档匮乏、范例匮乏,等等。

4.4 展望

GraphQL是业界的将来,这点毋庸置疑。目前不推荐使用,仅仅只是因为当前来看仍旧不成熟,工作量大,投入产出不成正比(特别是小型项目)。但对于大公司(比如目前已经到v4的Github API),GraphQL无疑是解决RESTful带来的一系列顽疾的良药。

期待后续的发展。

EOF

Published 2018/1/15

Some tech & personal blog posts