一、简介
什么是GraphQL?
GraphQL 是一种面向数据的 API 查询风格。
核心思想
传统的api调用一般获取到的是后端组装好的一个完整对象,而前端可能只需要用其中的某些字段,大部分数据的查询和传输工作都浪费了。GraphQL 对 API 中的数据提供了一套易于理解的完整描述,客户端能够准确地获得它需要的数据,没有任何冗余。
RESTful问题
RESTful是我们已经很熟悉的用于api通信的规范,如这样:
http://127.0.0.1/user //查询 GET
http://127.0.0.1/user //新增 PUT
http://127.0.0.1/user //更新
http://127.0.0.1/user //删除DELETE
在查询的时候,往往是这样:
//请求 GET http://127.0.0.1/user//1001
//响应:
{
id : 1001,
name : "张三",
age : 20,
address : "北京市",
……
}
这样看起来是没有问题的。如果对于这次请求,我只需要id和name属性,其他的属性我都不需要,但是我依然拿到的是全部的属性,这是不是一种资源浪费?
还有这样的一种场景,就是一次请求不能满足需求,需要有多次请求才能完成,像这样:
//查询用户信息
GET http://127.0.0.1/user/1001
//响应:
{
id : 1001,
name : "张三",
age : 20,
address : "北京市",
……
}
//查询用户的身份证信息
GET http://127.0.0.1/card/8888
//响应:
{
id : 8888,
name : "张三",
cardNumber : "999999999999999", address :"北京市",
……
}
查询用户以及他的身份证信息,需要进行2次查询才能够完成。这样对于前端等接口的使用方是很不友好的。那如果查询信息有10个,是不是要发起10次请求才能完成?
GraphQL很好的解决了RESTful在使用过程中的不足。
GraphQL和restful对比
restful:表示属性状态转移。本质上就是用定义uri,通过api接口来取得资源。通过系统架构不受语言限制。
restful | GraphQL |
---|---|
一个接口只能返回一个资源 | 一次可以获得多个资源 |
用不同的url来区分资源 | 用类型区分资源 |
restful和GraphQL的请求过程
-
restful
必须向不同的接口发出请求以获取所需的数据。同时也会拿到额外的数据,因为接口会返回其他不需要的信息。
-
GraphQL
在 GraphQL 中,我们只需向拥有数据的 GraphQL 服务端发送一条查询语句。服务端就会响应并返回带有查询结果的 JSON 对象。
特点
请求需要的数据,不多不少
可以看出,当请求中只有name属性时,响应结果中只包含name属性。如果请求中添加appearsIn属性,那么结果中就会返回appearsIn的值。
获取多个资源,只用一个请求
可以看出,一次请求,不仅查询到了hero数据,而且还查询到了friends数据。节省了网络请求次数。
描述所有可能类型的系统
便于维护,根据需求添加或者隐藏字段。
二、graphql案例
在GraphQL中,我们通过预先定义一个Schema和声明一些Type来达到上面提及的效果,我们需要知道:
- 对于数据模型的抽象是通过Type来描述的
- 对于接口获取数据的逻辑是通过Schema来描述的
Schema和Resolver
Schema
:它是用来描述对于接口获取数据逻辑的。在GraphQL中,我们用Query来描述资源的获取方式。因此,我们可以将Schema理解为多个Query组成的一张表。
GraphQL中使用Query来抽象数据的查询逻辑,当前标准下,有三种查询类型:
query
-当获取数据时,应当选取Query类型mutation
-尝试修改数据时,应当使用mutation类型subscription
—当希望数据更改时,可以进行消息推送,使用subscription类型
这三种基本查询类型是作为Root Query(根查询)存在的,对于传统的CRUD项目,我们只需要前两种类型就足够了,第三种是针对当前流行的real-time应用提出的。
query和mutation在Schema中的定义
Resolver
如果我们仅仅在Schema中声明了若干Query,那么我们只进行了一半的工作,因为我们并没有提供相关Query所返回数据的逻辑。为了能够使GraphQL正常工作,我们还需要再了解一个核心概念,Resolver(解析函数)。
GraphQL中,Query和与之对应的Resolver是同名的,这样在GraphQL才能把它们对应起来,举个例子,比如关于articles(): [Article!]!这个Query, 它的Resolver的名字必然叫做articles。
通过一个简单的例子来说明:
- 创建文件夹,使用
npm init
初始化该文件夹 - 安装用到的包 :
npm install express express-graphql graphql
- 创建入口文件server.js
const express = require('express');
var app = express()
//引入要用到的包
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');
// 构建Schema,定义查询的语句和类型
const schema = buildSchema(`
type Account{
name:String,
age:Int,
sex:String,
department:String
}
type Query {
hello:String,
accountName:String,
age:Int,
account:Account
}
` );
//定义查询对应的resolver,也就是查询对应的处理器
const root = {
name: 'Query',
hello: () => {
return 'Hello world!'
},
accountName: () => {
return '张三'
},
age: () => {
return '18'
},
account: () => {
return {
name: '李四',
age: 19,
sex: '女',
department: '北京'
}
}
}
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,//使用graphql的工具
}));
//
app.listen(4000, () => {
console.log('http://localhost:4000');
});
-
输入
http://localhost:4000/graphql
,如果看到以下页面,就说明graphql启动成功了!
-
接下来我们就可以根据自己需要的内容进行请求数据。