- 🏆🏆🏆 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
- 📣📣 欢迎大家多多点赞,关注!!!
前言
介绍GraphQL是什么的文章网上一搜一大把,篇幅有长有短,但是从最核心上讲,它是一种查询语言,再进一步说,是一种API查询语言。
这里可能有的人就会说,什么?API还能查?API不是用来调用的吗?是的,这正是GraphQL的强大之处,引用官方文档的一句话:
ask exactly what you want. 今天我们就来看下,grapql如何使用。
日常工作遇到的场景
- 一个详情页面,在迭代过程中不再展示某几个字段了,但是接口还是会返回那些数据,并且前端也不会用这些字段,久而久之,这样的字段就越来越多了
- 关于数据的返回格式,前端和后端需要沟通讨论很久,才能定一个一个双方都接收的情况
- 由于是底层公共接口,后端不能随便修改,导致某些接口前端实际使用到的字段仅仅一半不到
- 接口字段的格式不确定,经常变化
怎么办?
graphql可以解决以上这些问题
定义
- GraphQL 既是一种用于 API 的查询语言,也是一个满足你数据查询的运行时,它是由Facebook开发和开源的。
- GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
- GraphQL并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。
具体使用
我的理解:
- graphql实际就是在一层服务,我们可以在这一层进行数据结构的重组或者是修改,另外,这一层的开发人员可以是后端,也可以是前端。graphql.cn/code/
- 作为中间层,可以在客户端与服务端之间,作为服务,也可以直接在服务端做,有对应不同语言的工具库供选择
- graphql优秀的地方不仅仅在于数据组装,更在于可以让客户端(获取数据方)准确获取自己想要的数据结构,不多,也不少,并且数据格式也能够完全确定。
- 可视化数据查询
官方特点:
- 声明式数据获取(可以对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确实都可以解决:
- 前端想要的数据,前端自己决定,根据传的参数就可以决定返回的数据,灵活性很高
- 前端如何自己聚合接口,可以使用graphql,自己定义返回结构
- graphql会定义好数据结构,不会出现变更的情况
graphql缺点
- 目前还不能算热门,因为实现成本高,特别是对于一些前后端分工明确、或者是后端架构很成熟的公司,几乎是不太能推动的
- 可能会有查询冗余的情况
- 官方成熟的解决方案太少
使用
第一步:初始化一个项目,不用做太多配置,我们只是为了测试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服务器,同时输入查询语句,则可以进行可视化查询,如图
我们还可以进行一些更复杂的数据配置
// 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' } ];
}
}
}
})
});