GraphQl深入讲解和Express集成

GraphQl 介绍

GraphQL 是一种新的 API 的查询语言,它提供了一种更高效、强大和灵活 API 查询。它 是由 Facebook 开发和开源,目前由来自世界各地的大公司和个人维护。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且 没有任何冗余。它弥补了 RESTfulAPI(字段冗余,扩展性差、无法聚合 api、无法定义数据 类型、网络请求次数多)等不足。

注意:GraphQL 是 api 的查询语言,而不是数据库。从这个意义上说,它是数据库无关的, 而且可以在使用 API 的任何环境中有效使用,我们可以理解为 GraphQL 是基于 API 之上的一 层封装,目的是为了更好,更灵活的适用于业务的需求变化。

  1. GraphQL 可以用在常见各种服务器端语言以及客户端语言中
    服务器端语言:C#/.NET、Clojure、Elixir、Erlang、Go、Groovy、 Java、 JavaScript、PHP、Python、 Scala、Ruby

客户端语言: js、 React+ReactNative、 Angular、 Vue.js、 ApolloLink、NativeiOS、NativeAndroid、 Scala.js

中文文档

Github

  1. GraphQL 出现的历史背景

当提起API设计的时候,大家通常会想到SOAP(一种简单的基于 XML 的协议)
, RESTful 等设计方式,从 2000 年 RESTful 的理论被提出的时候,在业界引起了很大反响,因为这种 设计理念更易于用户的使用,所以便很快的被大家所接受。我们知道 REST 是一种从服务 器公开数据的流行方式。当 REST 的概念被提及出来时,客户端应用程序对数据的需求相 对简单,而开发的速度并没有达到今天的水平。因此 REST 对于许多应用程序来说是非常 适合的。然而在业务越发复杂,客户对系统的扩展性有了更高的要求时,API 环境发生了巨 大的变,RESTful 显得心有余而力不足。比如:字段冗余,扩展性差、无法聚合 api、无法 定义数据类型、网络请求次数多。

GraphQL 的出现整好弥补了 RESTfulAPi 的不足。

RESTfulAPI 不足

  1. 扩展性(多个终端需要返回不同的字段),单个RESTful接口返回数据越来越
    臃肿。前端对于真正用到的字段是没有直观映像的,仅仅通过url地址,无法预测也无
    法回忆返回的字段数目和字段是否有效,接口返回50个字段,但却只用5个字段,造
    成字段冗余,扩展性差,单个RESTful接口返回数据越来越臃肿。
  2. API聚合问题,某个前端展现,实际需要调用多个独立的 RESTful API 才能获
    取到足够的数据,导致网络请求次数多
  3. 前后端字段频繁改动,导致类型不一致,错误的数据类型可能会导致网站出错
    尤其是在业务多变的场景中,很难在保证工程质量的同时快速满足业务需求

GraphQL 的优点

  1. 吸收了RESTful API的特性。
  2. 所见即所得
    各种不同的前端框架和平台可以指定自己需要的字段。查询的返回结果就是输
    入的查询结构的精确映射
  3. 客户端可以自定义Api聚合。
    如果设计的数据结构是从属的,直接就能在查询语句中指定;即使数据结构是独
    立的,也可以在查询语句中指定上下文,只需要一次网络请求,就能获得资源和子
    资源的数据。
  4. 代码即是文档
    GraphQL 会把schema定义和相关的注释生成可视化的文档,从而使得代码
    的变更,直接就反映到最新的文档上,避免RESTful中手工维护可能会造成代码、文档不一致的问题。
  5. 参数类型强校验
    RESTful方案本身没有对参数的类型做规定,往往都需要自行实现参数的校验机制,
    以确保安全。
    但GraphQL提供了强类型的schema机制,从而天然确保了参数类型的合法性。

Express集成GraphQl

  1. 找到 express-graphql 官方文档

https://github.com/graphql/express-graphql

  1. 安装 express-graphql graphql

npm install express-graphql graphql--save

  1. 引入 express-graphql 配置中间件
var express=require('express'); /*引入*/
const graphqlHTTP = require('express-graphql');
var GraphQLSchema=require('./schema/default.js');
var app=express(); /*实例化*/
app.use('/graphql', graphqlHTTP({
schema: GraphQLSchema, graphiql: true
}));
app.get('/',function(req,res){
res.send('你好 express11');
})
app.listen(3000,'127.0.0.1');
  1. 定义 GraphQLSchema
  • 新建 schema/default.js
  • 定义 Schema
const DB = require('../model/db.js');
const {
    GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLSchema, GraphQLList
} = require('graphql');
//定义导航 Schema 类型
var GraphQLNav = new GraphQLObjectType({
    name: 'nav', fields: {
        title: { type: GraphQLString }, url: { type: GraphQLString }, sort: { type: GraphQLInt }, status: { type: GraphQLInt }, add_time: { type: GraphQLString }
    }
})
//定义根 根里面定义调用对应导航 Schema 类型的方法
var Root = new GraphQLObjectType({
    name: "RootQueryType", fields: {
        navList: {
            type: GraphQLList(GraphQLNav), async resolve(parent, args) {
                var navList = await DB.find('nav', {});
                console.log(navList)
                return navList;
            }
        }
    }
})
//挂载根
module.exports = new GraphQLSchema({
    query: Root
});

GraphQl 类型系统

可以将 GraphQL 的类型系统分为标量类型(Scalar Types,标量类型)和其他高级数据类型,标量类型即可以表示最细粒度数据结构的数据类型,可以和 JavaScript 的原始类型对应。

GraphQL 规范目前规定支持的标量类型有

Int:有符号 32 位整数。

  • Float:有符号双精度浮点值。
  • String:UTF‐8 字符序列。
  • Boolean:true 或者 false。
  • ID:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。

ID 类型使用和 String 一样的方式序列化;但是针对主键id时候,例如mongodb不需要getObjectID即可直接使用

GraphQL 其他高级数据类型包括

  1. Object :对象

用于描述层级或者树形数据结构。对于树形数据结构来说,叶子字段的类型都是标量数据类型。几乎所有 GraphQL 类型都是对象类型。Object 类型有一个 name 字段,以及一个很重要的 fields 字段。fields 字段可以描述出一个完整的数据结构。例如一个表示地址数据结构的 GraphQL 对象为。

const AddressType = new GraphQLObjectType({
    name: 'Address',
    fields: {
        street: { type: GraphQLString }, number: { type: GraphQLInt },
        formatted: {
            type: GraphQLString, resolve(obj) {
                return obj.number + ' ' + obj.street
            }
        }
    }
});
  1. Interface :接口用于描述多个类型的通用字
  2. Union :联合类型用于描述某个字段能够支持的所有返回类型以及具体请求真正的返回类型
  3. Enum :枚举用于表示可枚举数据结构的类型
  4. Input Object :输入对象
  5. List :列表

列表是其他类型的封装,通常用于对象字段的描述。例如下面PersonType 类型数据的parents 和 children 字段:

const PersonType = new GraphQLObjectType({
    name: 'Person',
    fields: () => ({
        parents: { type: new GraphQLList(Person) },
        children: { type: new GraphQLList(Person) },
    })
});
  1. Non-Null :不能为 Null

Non-Null 强制类型的值不能为 null,并且在请求出错时一定会报错。可以用于必须保证值不能为 null 的字段。例如数据库的行的 id 字段不能为 null:

const RowType = new GraphQLObjectType({
    name: 'Row',
    fields: () => ({
        id: { type: new GraphQLNonNull(GraphQLString) }
    })
});

GraphQl 查询语言

GraphQL 规范支持两种操作:

  • query:仅获取数据(fetch)的只读请求
  • mutation:获取数据后还有写操作的请求
    新版本的 GraphQL 还支持 subscription ,这是为了处理订阅更新(类似于消息队列)这种比较复杂的实时数据更新场景而设计的操作。


    图一.png

    图二.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容