GraphQL入门有这一篇就足够了

本文将从GraphQL是什么,为什么要使用GraphQL,使用GraphQL创建简单例子,以及GraphQL实战,四个方面对GraphQL进行阐述。说得不对的地方,希望大家指出斧正。

github项目地址:https://github.com/Charming2015/graphql-todolist

一、GraphQL是什么?

关于GraphQL是什么,网上一搜一大堆。根据官网的解释就是一种用于 API 的查询语言。

一看到用于API的查询语言,我也是一脸懵逼的。博主你在开玩笑吧?你的翻译水平不过关?API还能查吗?API不是后端写好,前端调用的吗?

的确可以,这就是GraphQL强大的地方。
引用官方文档的一句话:

ask exactly what you want.

二、为什么要使用GraphQL?

在实际工作中往往会有这种情景出现:比如说我需要展示一个游戏名的列表,可接口却会把游戏的详细玩法,更新时间,创建者等各种各样的 (无用的) 信息都一同返回。

问了后端,原因大概如下:

原来是为了兼容PC端和移动端用同一套接口
或者在整个页面,这里需要显示游戏的标题,可是别的地方需要显示游戏玩法啊,避免多次请求我就全部返回咯
或者是因为有时候项目经理想要显示“标题+更新时间”,有时候想要点击标题展开游戏玩法等等需求,所以把游戏相关的信息都一同返回

简单说就是:

   * 兼容多平台导致字段冗余
   * 一个页面需要多次调用 API 聚合数据
    * 需求经常改动导致接口很难为单一接口精简逻辑

有同学可能会说那也不一定要用GraphQL啊,比方说第一个问题,不同平台不同接口不就好了嘛

http://api.xxx.com/web/getGameInfo/:gameID
http://api.xxx.com/app/getGameInfo/:gameID
http://api.xxx.com/mobile/getGameInfo/:gameID

或者加个参数也行

http://api.xxx.com/getGameInfo/:gameID?platfrom=web

这样处理的确可以解决问题,但是无疑加大了后端的处理逻辑。你真的不怕后端程序员打你?

这个时候我们会想,接口能不能不写死,把静态变成动态?

回答是可以的,这就是GraphQL所做的!

三、GraphQL尝尝鲜——(GraphQL简单例子)

下面是用GraphQL.js和express-graphql搭建一个的普通GraphQL查询(query)的例子,包括讲解GraphQL的部分类型和参数,已经掌握了的同学可以跳过。

  1. 先跑个hello world

新建一个graphql文件夹,然后在该目录下打开终端,执行npm init --y初始化一个packjson文件。
安装依赖包:npm install --save -D express express-graphql graphql
新建sehema.js文件,填上下面的代码

//schema.js
const {
      GraphQLSchema,
      GraphQLObjectType,
      GraphQLString,
    } = require('graphql');
const queryObj = new GraphQLObjectType({
    name: 'myFirstQuery',
    description: 'a hello world demo',
    fields: {
        hello: {
            name: 'a hello world query',
            description: 'a hello world demo',
            type: GraphQLString,
            resolve(parentValue, args, request) {
                return 'hello world !';
            }
        }
    }
});
module.exports = new GraphQLSchema({
  query: queryObj
});

这里的意思是新建一个简单的查询,查询名字叫hello,会返回字段hello world !,其他的是定义名字和查询结果类型的意思。

同级目录下新建server.js文件,填上下面的代码

// server.js
const express = require('express');
const expressGraphql = require('express-graphql');
const app = express();

const schema = require('./schema');
app.use('/graphql', expressGraphql({
    schema,
    graphiql: true
}));

app.get('/', (req, res) => res.end('index'));

app.listen(8000, (err) => {
  if(err) {throw new Error(err);}
  console.log('*** server started ***');
});

这部分代码是用express跑起来一个服务器,并通过express-graphql把graphql挂载到服务器上。

运行一下node server,并打开http://localhost:8000/

GraphQL入门有这一篇就足够了_第1张图片
图片.png

如图,说明服务器已经跑起来了
打开 http://localhost:8000/graphql,是类似下面这种界面说明已经graphql服务已经跑起来了!
GraphQL入门有这一篇就足够了_第2张图片
这里写图片描述

在左侧输入 (graphql的查询语法这里不做说明)

{
  hello
}

点击头部的三角形的运行按钮,右侧就会显示你查询的结果了


GraphQL入门有这一篇就足够了_第3张图片
这里写图片描述
2. 不仅仅是hello world

先简单讲解一下代码:

const queryObj = new GraphQLObjectType({
    name: 'myFirstQuery',
    description: 'a hello world demo',
    fields: {}
});

GraphQLObjectType是GraphQL.js定义的对象类型,包括name、description 和fields三个属性,其中name和description 是非必填的。fields是解析函数,在这里可以理解为查询方法

hello: {
            name: 'a hello world query',
            description: 'a hello world demo',
            type: GraphQLString,
            resolve(parentValue, args, request) {
                return 'hello world !';
            }
        }

对于每个fields,又有name,description,type,resolve参数,这里的type可以理解为hello方法返回的数据类型,resolve就是具体的处理方法。

说到这里有些同学可能还不满足,如果我想每次查询都想带上一个参数该怎么办,如果我想查询结果有多条数据又怎么处理?

下面修改schema.js文件,来一个加强版的查询(当然,你可以整理一下代码,我这样写是为了方便阅读)

const {
      GraphQLSchema,
      GraphQLObjectType,
      GraphQLString,
      GraphQLInt,
      GraphQLBoolean
    } = require('graphql');

const queryObj = new GraphQLObjectType({
    name: 'myFirstQuery',
    description: 'a hello world demo',
    fields: {
        hello: {
            name: 'a hello world query',
            description: 'a hello world demo',
            type: GraphQLString,
            args: {
                name: {  // 这里定义参数,包括参数类型和默认值
                    type: GraphQLString,
                    defaultValue: 'Brian'
                }
            },
            resolve(parentValue, args, request) { // 这里演示如何获取参数,以及处理
                return 'hello world ' + args.name + '!';
            }
        },
        person: {
            name: 'personQuery',
            description: 'query a person',
            type: new GraphQLObjectType({ // 这里定义查询结果包含name,age,sex三个字段,并且都是不同的类型。
                name: 'person',
                fields: {
                  name: {
                    type: GraphQLString
                  },
                  age: {
                    type: GraphQLInt
                  },
                  sex: {
                    type: GraphQLBoolean
                  }
                }
            }),
            args: {
                name: {
                    type: GraphQLString,
                    defaultValue: 'Charming'
                }
            },
            resolve(parentValue, args, request) {
                return {
                    name: args.name,
                    age: args.name.length,
                    sex: Math.random() > 0.5
                };
            }
        }
    }
});

module.exports = new GraphQLSchema({
  query: queryObj 
});

重启服务后,继续打开http://localhost:8000/graphql,在左侧输入

{
  hello(name:"charming"),
  person(name:"charming"){
    name,
    sex,
    age
  }
}

右侧就会显示出:


GraphQL入门有这一篇就足够了_第4张图片
图片.png

你可以在左侧仅输入person方法的sex和age两个字段,这样就会只返回sex和age的信息。动手试一试吧!

{
  person(name:"charming"){
    sex,
    age
  }
}

当然,结果的顺序也是按照你输入的顺序排序的。

定制化的数据,完全根据你查什么返回什么结果。这就是GraphQL被称作API查询语言的原因。

四、GraphQL实战

下面我将搭配koa实现一个GraphQL查询的例子,逐步从简单koa服务到mongodb的数据插入查询,再到GraphQL的使用,最终实现用GraphQL对数据库进行增删查改。

项目效果大概如下:

20180905142957816.gif

有点意思吧?那就开始吧~
先把文件目录建构建好

  1. 初始化项目

    初始化项目,在根目录下运行npm init --y,
    然后安装一些包:npm install koa koa-static koa-router koa-bodyparser --save -D
    新建config、controllers、graphql、mongodb、public、router这几个文件夹。装逼的操作是在终端输入mkdir config controllers graphql mongodb public router回车,ok~

  2. 跑一个koa服务器
    新建一个server.js文件,写入以下代码

// server.js
import Koa from 'koa'
import Router from 'koa-router'
import bodyParser from 'koa-bodyparser'

const app = new Koa()
const router = new Router();
const port = 4000

app.use(bodyParser());

router.get('/hello', (ctx, next) => {
  ctx.body="hello world"
});


app.use(router.routes())
   .use(router.allowedMethods());

app.listen(port);

console.log('server listen port: ' + port)

这里的意思是新建一个简单的查询,查询名字叫hello,会返回字段hello world !,其他的是定义名字和查询结果类型的意思。

同级目录下新建server.js文件,填上下面的代码

// server.js
const express = require('express');
const expressGraphql = require('express-graphql');
const app = express();

const schema = require('./schema');
app.use('/graphql', expressGraphql({
    schema,
    graphiql: true
}));

app.get('/', (req, res) => res.end('index'));

app.listen(8000, (err) => {
  if(err) {throw new Error(err);}
  console.log('*** server started ***');
});

这部分代码是用express跑起来一个服务器,并通过express-graphqlgraphql挂载到服务器上。

  1. 运行一下node server,并打开http://localhost:8000/
GraphQL入门有这一篇就足够了_第5张图片
这里写图片描述

如图,说明服务器已经跑起来了
打开http://localhost:8000/graphql,是类似下面这种界面说明已经graphql服务已经跑起来了!

GraphQL入门有这一篇就足够了_第6张图片
图片.png

在左侧输入 (graphql的查询语法这里不做说明)

{
  hello
}

点击头部的三角形的运行按钮,右侧就会显示你查询的结果了


GraphQL入门有这一篇就足够了_第7张图片
图片.png
  1. 不仅仅是hello world

先简单讲解一下代码:

const queryObj = new GraphQLObjectType({
    name: 'myFirstQuery',
    description: 'a hello world demo',
    fields: {}
});

GraphQLObjectType是GraphQL.js定义的对象类型,包括name、description 和fields三个属性,其中name和description 是非必填的。fields是解析函数,在这里可以理解为查询方法

hello: {
            name: 'a hello world query',
            description: 'a hello world demo',
            type: GraphQLString,
            resolve(parentValue, args, request) {
                return 'hello world !';
            }
        }

对于每个fields,又有name,description,type,resolve参数,这里的type可以理解为hello方法返回的数据类型,resolve就是具体的处理方法。

说到这里有些同学可能还不满足,如果我想每次查询都想带上一个参数该怎么办,如果我想查询结果有多条数据又怎么处理?

下面修改schema.js文件,来一个加强版的查询(当然,你可以整理一下代码,我这样写是为了方便阅读)

const {
      GraphQLSchema,
      GraphQLObjectType,
      GraphQLString,
      GraphQLInt,
      GraphQLBoolean
    } = require('graphql');

const queryObj = new GraphQLObjectType({
    name: 'myFirstQuery',
    description: 'a hello world demo',
    fields: {
        hello: {
            name: 'a hello world query',
            description: 'a hello world demo',
            type: GraphQLString,
            args: {
                name: {  // 这里定义参数,包括参数类型和默认值
                    type: GraphQLString,
                    defaultValue: 'Brian'
                }
            },
            resolve(parentValue, args, request) { // 这里演示如何获取参数,以及处理
                return 'hello world ' + args.name + '!';
            }
        },
        person: {
            name: 'personQuery',
            description: 'query a person',
            type: new GraphQLObjectType({ // 这里定义查询结果包含name,age,sex三个字段,并且都是不同的类型。
                name: 'person',
                fields: {
                  name: {
                    type: GraphQLString
                  },
                  age: {
                    type: GraphQLInt
                  },
                  sex: {
                    type: GraphQLBoolean
                  }
                }
            }),
            args: {
                name: {
                    type: GraphQLString,
                    defaultValue: 'Charming'
                }
            },
            resolve(parentValue, args, request) {
                return {
                    name: args.name,
                    age: args.name.length,
                    sex: Math.random() > 0.5
                };
            }
        }
    }
});

module.exports = new GraphQLSchema({
  query: queryObj 
});

重启服务后,继续打开http://localhost:8000/graphql,在左侧输入

{
  hello(name:"charming"),
  person(name:"charming"){
    name,
    sex,
    age
  }
}

右侧就会显示出:


GraphQL入门有这一篇就足够了_第8张图片
图片.png

你可以在左侧仅输入person方法的sex和age两个字段,这样就会只返回sex和age的信息。动手试一试吧!

{
  person(name:"charming"){
    sex,
    age
  }
}

当然,结果的顺序也是按照你输入的顺序排序的。

定制化的数据,完全根据你查什么返回什么结果。这就是GraphQL被称作API查询语言的原因。

四、GraphQL实战

参考:https://blog.csdn.net/qq_41882147/article/details/82966783

你可能感兴趣的:(GraphQL入门有这一篇就足够了)