傍晚,RESTful的发明者罗伊悄悄来到咖啡馆。他想看看他引以为豪的RESTful是怎么用的。(RESTful的故事可以参考《RPC发展简史》)门口旁边的桌子上坐着一群人。他们还在讨论老套的JavaRMI,好像遇到了一些技术难关。看来不管是什么技术,都会有非常老旧的遗留系统需要维护。多么努力的程序员啊,罗伊感叹道。这里有一群人在讨论谷歌的Protobuf。看来序列化有了很大的进步,可以实现跨语言的序列化了。再往里走,终于有人讨论RESTful了!罗伊感到兴奋。只听到一个人说:“我们领导刚开始强制使用RESTful面向资源的风格,大家都挺新奇的,但是用了之后,又要回到那种面向功能的方式了。”“对对对,我还是比较习惯传统的RPC方式,比较直观,尤其是用了Dubbo之后,函数式的风格应该不会太cool吧。”罗伊有些失望。RESTful缺陷“其实,RESTful有一个缺陷,你注意到了吗?”一位名叫格拉夫的男子忽然说道。“怎么了?”“我给你举个例子,”Graf说,“比如我有两个资源,一个叫Article,一个叫User。”“这是正常的,可以增删改查资源。”罗伊说着,他的话也引起了周围人的共鸣。“听我说,我现在要开发一个移动端,我想展示一个文章列表,假设界面原型是这样的:”“第一步,我需要获取这些文章的列表,你可以GET/articles""没关系!这不就是获取资源表示的常用方式吗?"人群中有人说道。但是罗伊却敏锐的发现,界面中需要一张“作者头像”。显然,这张作者头像并没有保存在Article资源中,而是保存在User中。返回结果中只返回author_id。如果想获取作者头像,需要循环返回文章列表,取出author_id,再通过/users资源查询。当罗伊亮出这个查询的时候,周围的人群顿时炸开了锅:“文章有多少,可以追加多少个查询?!实际操作中,绝对不能这样!”有人说:“我们只是需要头像信息(avatar_url),你为什么要返回那么多乱七八糟的性别、年龄、last_login_time!”“这个RESTful真的很糟糕!”Roy有点尴尬,没想到我的RESTful会出现这样两个问题:1.发送请求过多(每篇文章都要查询附加作者信息)2.附加信息过多(其实只想要avatar_url字段)想到这里,罗伊的心顿时沉了下去,怎么解决这个问题呢?中间层的老祖宗教导我们:计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决!这个中间层是什么?Roy想到前后端没有分离的时候,页面都是为了后端渲染,程序员会创建一个VO(ViewObject),里面会封装所有界面显示需要的信息,然后发送给JSP使用。在RESTful中,您还可以创建VO之类的资源。想到这里,他对格拉夫说:“你为什么不创建一个像HotArticle这样的资源呢?”这个HotArticle可以结合文章和作者。只返回接口需要的数据。Graff说:“这样不好,这个HotArticle资源相当于深度绑定了界面,如果界面要改,这个HotArticle也得改,很麻烦。”罗伊道:“那我们一起换吧,反正两者是一致的。”“不是,还有更复杂的情况,假设界面发生了变化,需要将作者头像换成文章封面图,这时候怎么办?”罗伊道:“我明白你的意思了,不是说新旧手机都支持吗?很简单,有两种方案。”(1)复用HotArticle,保留原有avatar_url,新增字段article_img_url,不同手机各取所需新版本。”第一个方案不错!很简单!”人群中有人说道。“好吧,如果手机界面一直在变,如果你用第一种方式,那个HotArticle很快就会变成垃圾场,没有准确的文档,你根本不知道哪个字段被谁用了!”“第二,这个方案会有很多版本,假设你想改变一些普遍的东西,比如增加一篇文章的阅读量,那不就得全部改了吗?”可以看出这两种方式各有优缺点,不断变化都有问题,也不是很完美,这也是后端资源和前端接口绑定的结果灵活查询Roy陷入沉思:移动端能不能按需查询?服务端维护最简单的Article和User概念,把他们当成两张表,如果查出来,可以类似Join的功能。想到这个,他写了这样一条SQL:selecta.id,a.title,a.abstract,a.liked_count,u.avatar_urlfromArticlea,Useruwherea.author_id=u.id看到这张图,全场掌声雷动:“还是用SQL好!”唯有格拉夫冷冷道:“SQL的局限太多了。比如我想同时在手机端显示作者的好友。文章和作者是一一对应的,但是作者可能有多个朋友,所以SQL结果集中会有重复的文章id、标题、摘要。”罗伊说:“那你怎么办?说?”关系模型在表达这种关联时很不方便,我发明了一种新的模型和一种新的查询语言,让我们看看。怪异查询Graf展示了一个查询方法:快看一下,这个查询太怪异了,语法是什么?虽然怪异,但是很实用,准确描述了这个需求:我需要一个id为11的用户,然后fetchmehisname,age,avatar_url等字段,其他字段不用传,查询结果也是标准的JSON格式,与要查询的内容一一对应,非常容易理解。罗伊问道:“没关系,你之前的问题是怎么解决的?”Graf展示了另一个查询,这次稍微复杂一点:“看到了吗?这次代表了一个文章列表,每个文章元素都有id、title、abstract、liked_count等字段。还有一个特殊的字段叫做author,相当于在article中嵌套了一个元素,这个author元素还有一个字段叫avatar_url。”众人看着,都觉得很有意思。这样,前面的问题就彻底解决了。只需查询一次,文章连同作者头像一起发回,更重要的是没有乱七八糟的额外信息。如果要添加作者的好友信息,可以将查询改成下面这样,非常灵活。见状,罗伊有些明白了。这是一种新的查询方式,不同于关系型数据库的SQL,也不同于RESTful。显然,后端的数据模型也必须改变。他问:“你的后台数据模型是Graph吗?”Graf赞道:“你可以看到,太神奇了。为了支持这样的查询,后台的数据模型是一个图:”“根据这张图,我可以找到任何数据,从文章中找到作者,找到相关的作者的朋友们……只要你们把关系搞好,我没有什么做不到的。”“那些文章,用户类型及其属性也应该明确定义吗?”罗伊又问道。格拉夫赞赏地看了罗伊一眼,说道:“没错,可以这么定义。”一目了然,大家都很喜欢!“这种新的查询语言叫什么名字?”“我叫Graph,所以这个查询语言就叫GraphQL!”【本文为专栏作家“刘欣”原创稿件,转载请通过作者微信获取授权公众号coderising】点此查看作者更多好文
