GraphQl 介绍
GraphQL 是一种新的 API 的查询语言,它提供了一种更高效、强大和灵活 API 查询。它 是由 Facebook 开发和开源,目前由来自世界各地的大公司和个人维护。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且 没有任何冗余。它弥补了 RESTfulAPI(字段冗余,扩展性差、无法聚合 api、无法定义数据 类型、网络请求次数多)等不足。
注意:GraphQL 是 api 的查询语言,而不是数据库。从这个意义上说,它是数据库无关的, 而且可以在使用 API 的任何环境中有效使用,我们可以理解为 GraphQL 是基于 API 之上的一 层封装,目的是为了更好,更灵活的适用于业务的需求变化。
- 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
- GraphQL 出现的历史背景
当提起API设计的时候,大家通常会想到SOAP(一种简单的基于 XML 的协议)
, RESTful 等设计方式,从 2000 年 RESTful 的理论被提出的时候,在业界引起了很大反响,因为这种 设计理念更易于用户的使用,所以便很快的被大家所接受。我们知道 REST 是一种从服务 器公开数据的流行方式。当 REST 的概念被提及出来时,客户端应用程序对数据的需求相 对简单,而开发的速度并没有达到今天的水平。因此 REST 对于许多应用程序来说是非常 适合的。然而在业务越发复杂,客户对系统的扩展性有了更高的要求时,API 环境发生了巨 大的变,RESTful 显得心有余而力不足。比如:字段冗余,扩展性差、无法聚合 api、无法 定义数据类型、网络请求次数多。
GraphQL 的出现整好弥补了 RESTfulAPi 的不足。
RESTfulAPI 不足
- 扩展性(多个终端需要返回不同的字段),单个RESTful接口返回数据越来越
臃肿。前端对于真正用到的字段是没有直观映像的,仅仅通过url地址,无法预测也无
法回忆返回的字段数目和字段是否有效,接口返回50个字段,但却只用5个字段,造
成字段冗余,扩展性差,单个RESTful接口返回数据越来越臃肿。 - API聚合问题,某个前端展现,实际需要调用多个独立的 RESTful API 才能获
取到足够的数据,导致网络请求次数多 - 前后端字段频繁改动,导致类型不一致,错误的数据类型可能会导致网站出错
尤其是在业务多变的场景中,很难在保证工程质量的同时快速满足业务需求
GraphQL 的优点
- 吸收了RESTful API的特性。
- 所见即所得
各种不同的前端框架和平台可以指定自己需要的字段。查询的返回结果就是输
入的查询结构的精确映射 - 客户端可以自定义Api聚合。
如果设计的数据结构是从属的,直接就能在查询语句中指定;即使数据结构是独
立的,也可以在查询语句中指定上下文,只需要一次网络请求,就能获得资源和子
资源的数据。 - 代码即是文档
GraphQL 会把schema定义和相关的注释生成可视化的文档,从而使得代码
的变更,直接就反映到最新的文档上,避免RESTful中手工维护可能会造成代码、文档不一致的问题。 - 参数类型强校验
RESTful方案本身没有对参数的类型做规定,往往都需要自行实现参数的校验机制,
以确保安全。
但GraphQL提供了强类型的schema机制,从而天然确保了参数类型的合法性。
Express集成GraphQl
- 找到 express-graphql 官方文档
https://github.com/graphql/express-graphql
- 安装 express-graphql graphql
npm install express-graphql graphql--save
- 引入 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');
- 定义 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 其他高级数据类型包括
- 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
}
}
}
});
- Interface :接口用于描述多个类型的通用字
- Union :联合类型用于描述某个字段能够支持的所有返回类型以及具体请求真正的返回类型
- Enum :枚举用于表示可枚举数据结构的类型
- Input Object :输入对象
- List :列表
列表是其他类型的封装,通常用于对象字段的描述。例如下面PersonType 类型数据的parents 和 children 字段:
const PersonType = new GraphQLObjectType({
name: 'Person',
fields: () => ({
parents: { type: new GraphQLList(Person) },
children: { type: new GraphQLList(Person) },
})
});
- 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 ,这是为了处理订阅更新(类似于消息队列)这种比较复杂的实时数据更新场景而设计的操作。