Egg.js中使用GraphQL-简单实战

GraphQL实战

1. GrqphQL是什么

GraphQL是一种面向数据的API查询风格。javascript

GraphQL是由Facebook主导开发的一款面向数据的API查询语言。客户端只需给他一个描述,而后GraphQL就能从数据库组合出符合描述的数据并返回。前端

2. GraphQL解决了什么问题

在开发中咱们通常都使用的是RESTful API,它是是面向资源的。一般渲染一个页面咱们须要多个资源,REST API请求多个资源时就会载入多个URL,而GraphQL能够经过一次请求就能够获取到须要的全部数据。java

解决痛点:数据库

  • 接口返回数据格式并非调用者(前端)理想型npm

  • 多个资源只用一个请求,减小服务器压力json

  • 数据字段由调用者控制后端

GraphQL 既是一种用于 API 的查询语言也是一个知足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端可以准确地得到它须要的数据,并且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。数组

示例:浏览器

这里以掘金的首页举例,它可能分为这几个资源(文章列表,分类列表,做者榜)bash

REST API

文章列表/articles

[
    {
        title: 'xxx',
        content: 'xxx内容'
    }
]
复制代码

分类列表/categories

[
	{
		id: '1'
		name: '前端',
	},
	{
		id: '2'
		name: '后端',
	},
]
复制代码

做者推荐榜/recommendationAuthor

[
    {
        id: 1,
        username: '张三'
    }
]
复制代码

上面是用REST接口来获取首页须要的数据,须要发送3次请求,再看下GraphQL的请求是什么样?

GraphQL查询接口/graphql/query

query getHomePage() {
	articleList($first: 0) {
		title
        content
    },
    categoryList(){
        id
        name
    },
    recommendationAuthorList($limit: 10) {
        id
        username
    },
      
} 
复制代码

经过Graphql只用请求一次就能够拿到所有信息,返回的数据格式都是由调用者控制的,很少很多。

3 GraphQL重要概念

这里先介绍几个GraphQL比较重要的概念,能够参考着GraphQL官网文档看。

3.1 操做类型

操做类型能够是query、mutation、substription ,描述你打算作什么类型的操做。

  1. query 查询
  2. mutation 变动
  3. substription 订阅,当数据更新后,会推送消息

每个Graphql都有一个query类型,也可能有一个mutation类型。他们定义了每个Graphql查询的入口。

3.2 标量类型

  • Int 有符号32位整数
  • Float 有符号双精度浮点数
  • String UTF-8字符序列
  • Boolean true或者false
  • ID ID标量类型标识一个惟一标识符

3.3 对象类型和字段

type Article{
	title: String
	author: [User]
}
复制代码

上面我声明了一个GraphQL对象类型,这里声明了两个字段并指定了字段类型。

String是内置的标量类型之一,查询中没法对他进行次级选择。

[User] 表示一个User数组,数组中的每一个项目都是一个User对象。

  • User对象怎么来的呢?

    如Article同样 使用type关键字声明

    type User {
    	name: String
    	age: Int
    }
    复制代码
  • 声明对象有什么用?

    经过Query对外提供查询入口时,咱们一般都是以一个对象为一个单位。能够把每一个对象看做成一个接口。

3.3 输入类型

经过Mutation对外提供变动入口。有时你须要传递一整个对象做为新建对象,以前的标量类型就不能知足了。

官网示例:

4. egg-graphql实战

客户端使用前,咱们须要在服务端定义Schema结构。

4.1 使用脚手架生成Egg项目

PS: 下载太慢时能够先全局安装egg-init脚手架,再执行egg-init --type simple --registry china使用淘宝镜像生成项目

4.2 安装graphql插件

  1. 执行npm i egg-apollo-server --save

  2. 在egg项目中添加graphql的相关配置, 详见egg-apollo-server

​ 这里我没有用egg-graphql插件而使用的是egg-apollo-server

PS:config.graphql.subscriptions用来对grapql请求作鉴权的,在此demo里不须要改成false便可

4.3 定义schema

├── app
│   ├── controller
│   │   └── home.js
│   ├── graphql
│   │   ├── article
│   │   │   ├── resolver.js
│   │   │   └── schema.graphql
│   ├── router.js
│   └── service
├── config
│   ├── config.default.js
│   └── plugin.js
├── package.json
└── package-lock.json
复制代码
  • schema.graphql

    定义GraphQL类型和操做

    extend type Query {
        articleList(first: ID): [Article]
    }
    
    type Article {
        id: ID
        title: String
        content: String
        author: Author
    }
    type Author {
        name: String
        age: Int
    }
    
    extend type Mutation {
        addArticle(title: String, content: String, author: AddAuthor): Article
    }
    
    input AddArticle {
        title: String
        content: String
    }
    
    input AddAuthor {
        name: String
        age: Int
    }
    复制代码
  • resolver.js

    实现操做

    'use strict';
    const list = [
      {
        id: 1,
        content: 'aaa',
        title: '',
        author: {
          name: 'aaa',
          age: 18,
        },
      },
      {
        id: 2,
        content: 'bbb',
        title: '',
        author: {
          name: 'aaa',
          age: 18,
        },
      },
    ];
    module.exports = {
      Query: {
        articleList: () => {
          return list;
        },
    
      },
      Mutation: {
        addArticle(root, params, ctx) {
          console.log(params);
          params.id = list.length++;
          list.push(params);
          return params;
        },
      },
    };
    
    复制代码

4.4 graphql调试

浏览器打开 http://127.0.0.1:7001/graphql进行调试

PS: 测试前须要关闭csrf保护,不然调试发送的post请求将会被拦截

左侧为查询区,在这里写操做语句。右侧为执行结果。

查询调试

{
  articleList(first: 0){
    id
    title
    content
    author{
			name
      age
    }
	}
}
复制代码

变动调试

mutation {
  addArticle(title: "title", content: "content", author: {name: "张三", age: 15}){
    title
    content
    id
  }
}
复制代码