如何使用graphql定义更舒适的结构

585 阅读6分钟
  • 🏆🏆🏆 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
  • 📣📣 欢迎大家多多点赞,关注!!!

前言

介绍GraphQL是什么的文章网上一搜一大把,篇幅有长有短,但是从最核心上讲,它是一种查询语言,再进一步说,是一种API查询语言。

这里可能有的人就会说,什么?API还能查?API不是用来调用的吗?是的,这正是GraphQL的强大之处,引用官方文档的一句话:

ask exactly what you want. 今天我们就来看下,grapql如何使用。

日常工作遇到的场景

  1. 一个详情页面,在迭代过程中不再展示某几个字段了,但是接口还是会返回那些数据,并且前端也不会用这些字段,久而久之,这样的字段就越来越多了
  2. 关于数据的返回格式,前端和后端需要沟通讨论很久,才能定一个一个双方都接收的情况
  3. 由于是底层公共接口,后端不能随便修改,导致某些接口前端实际使用到的字段仅仅一半不到
  4. 接口字段的格式不确定,经常变化

怎么办?

graphql可以解决以上这些问题

graphql.gif

定义

  • GraphQL 既是一种用于 API 的查询语言,也是一个满足你数据查询的运行时,它是由Facebook开发和开源的。
  • GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
  • GraphQL并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

具体使用

详细使用

我的理解:

  1. graphql实际就是在一层服务,我们可以在这一层进行数据结构的重组或者是修改,另外,这一层的开发人员可以是后端,也可以是前端。graphql.cn/code/
  2. 作为中间层,可以在客户端与服务端之间,作为服务,也可以直接在服务端做,有对应不同语言的工具库供选择
  3. graphql优秀的地方不仅仅在于数据组装,更在于可以让客户端(获取数据方)准确获取自己想要的数据结构,不多,也不少,并且数据格式也能够完全确定。
  4. 可视化数据查询

官方特点:

  • 声明式数据获取(可以对API进行查询): 声明式的数据查询带来了接口的精确返回,服务器会按数据查询的格式返回同样结构的 JSON 数据、真正照顾了客户端的灵活性。
  • 一个微服务仅暴露一个 GraphQL 层:一个微服务只需暴露一个GraphQL endpoint,客户端请求相应数据只通过该端点按需获取,不需要再额外定义其他接口。
  • 传输层无关、数据库技术无关:带来了更灵活的技术栈选择,比如我们可以选择对移动设备友好的协议,将网络传输数据量最小化,实现在网络协议层面优化应用。

graphql支持的操作:

  • 查询(Query):获取数据的基本查询。

  • 变更(Mutation):支持对数据的增删改等操作。

    mutation{
      insert(
        title: "111"
        genres: "jhsj"
        rating: 9.4
        theater: 2
      ) {
        id
      }
    }
  • 订阅(Subscription):用于监听数据变动、并靠websocket等协议推送变动的消息给对方。

graphql数据模型

要使用graphql,需要给每一个接口都定义graphql数据模型,而定义数据模型,就需要有一个schema语法进行支撑,也就是graphql语法,这里就不进行赘述,大概写法如下:

  • 有点像定义数据库似的,我们需要显示声明每一个字段的数据结构
  • graphql写法也不太一样,有好几种写法,如下只是一种写法,GraphQLSchema
let MovieType = new GraphQLObjectType({
    name: 'MovieType',
    fields: {
        user_name: {
            type: GraphQLString
        },
        company: {
            type: GraphQLString
        },
        user_id: {
            type: GraphQLString
        },
        got_digg_count: {
            type: GraphQLInt
        },
        got_view_count: {
            type: GraphQLInt
        },
        description: {
            type: GraphQLString
        }
    }
})

还有一种写法是 buildSchema

const schema = buildSchema(`
    type SignType {
        accessid: String,
        dir: String,
        expire: Int,
        host: String,
        policy: String,
        signature: String
    }
    type CommonType {
        id: String
    }
    type Query {
        hello: String,
        sign(cate: String!): SignType
        common(type: String, city_id: String, order_id: String): CommonType
    }
`);

通过对graphql的理解,可以发现,对于上面说的场景问题,graphql确实都可以解决:

  1. 前端想要的数据,前端自己决定,根据传的参数就可以决定返回的数据,灵活性很高
  2. 前端如何自己聚合接口,可以使用graphql,自己定义返回结构
  3. graphql会定义好数据结构,不会出现变更的情况

graphql缺点

  1. 目前还不能算热门,因为实现成本高,特别是对于一些前后端分工明确、或者是后端架构很成熟的公司,几乎是不太能推动的
  2. 可能会有查询冗余的情况
  3. 官方成熟的解决方案太少

使用

第一步:初始化一个项目,不用做太多配置,我们只是为了测试graphql,所以创建项目的话一路回车就行

 npm init

第二步:下载graphql相关,因为我们想要在node中潜入graphql,使用框架是express,所以需要express和express-graphql

yarn add graphql express express-graphql

第三步:下载babel相关,因为我写graphql可能需要用到一些es6写法(暂时不用)

yarn add @babel/cli @babel/core @babel/node

第四步配置package.json

"scripts": {
	// nodemon如果没有,需要下载
    "dev": "nodemon index.js --exec babel-node --presets @babel/preset-env",
    "test": "echo "Error: no test specified" && exit 1"
  }

第五步,创建一个index.js,用express启动一个服务:http://localhost:5000

import express from 'express';
const app = express();
app.use((req, res) => {
    res.send('welcome');
})
app.listen(5000);

下面,我们就可以进行graphql配置了

// index.js
import {
    graphqlHTTP
} from 'express-graphql';
import GraphqlSchema from './GraphqlSchema';
const app = express();
// 启动一个graphql服务,可以进行可视化查询操作
app.use(
    '/graphql',
    graphqlHTTP({
        schema: GraphqlSchema,
        graphiql: true,
    }),
);
app.listen(5000);

新建一个graphqlSchema.js文件,进行graphql的schema配置

import {
    graphql,
    GraphQLSchema,
    GraphQLObjectType,
    GraphQLString,
    GraphQLList,
    GraphQLInt
} from 'graphql';

var schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: 'RootQueryType',
        fields: {
            hello: {
                type: GraphQLString,
                resolve() {
                    return 'world';
                },
            }
        }
    })
});

export default schema;

启动命令:

npm run dev

在浏览器中输入:http://localhost:5000/graphql即可启动graphql服务器,同时输入查询语句,则可以进行可视化查询,如图

image.png

我们还可以进行一些更复杂的数据配置

// GraphqlSchema.js
let HelloType = new GraphQLObjectType({
    name: 'HelloType',
    fields: {
        name: {
            type: GraphQLString
        },
        age: {
            type: GraphQLInt
        },
        phone: {
            type: GraphQLString
        }
    }
})

var schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: 'RootQueryType',
        fields: {
            hello: {
                type: new GraphQLList(HelloType),
                resolve() {
                    return [                        {                            name: 'tom',                            age: 18,                            phone: '323243434'                        },                        {                            name: 'jerry',                            age: 10,                            phone: '1123333'                        },                        {                            name: 'hahah',                            age: 48,                            phone: '222233444'                        }                    ];
                }
            }
        }
    })
});

参考文章

github.com/chentsulin/…

我为什么放弃restfull来拥抱graphql?

graphql-前端