GraphQL-前端开发的利剑与桥梁

基本概念

GraphQL

GraphQL 是一种用于 API 的查询语言,由Facebook开发和开源,是使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

背景介绍

相信看了上面的基本概念,大家都是和我一样一脸萌萌哒。所以这里就需要介绍一下其产生的背景和原因。

在我们目前的前后端开发过程中,大部分都是以http请求服务端接口的方式完成交互过程的。在这种场景下,每当需求变化,就需要修改或创建一个新的接口去满足特定的需求。

举个栗子:

在一个商品详情页,当我们需要获取商品详情时,服务端会给前端一个接口,例如:

https://www.example.com/getInfoById?infoId=000000

当前端请求接口时,会返回给一个固定格式的数据,例如:


data:{
title:'商品的标题',
content:'商品的描述内容',
special:'商品特点',
price:'商品价格',
image:'商品的图片'
}

前端接收到数据后,进行各种相应的处理展示,最终将包含有商品标题,商品描述,商品特点,商品价格,商品图片信息的页面展示给用户。

一切看起来都很美好,直到有一天……

产品大摇大摆的走过来,轻描淡写的说道:“能不能把商品的特点去掉,加一个商品的库存,另外还需要再加一个卖家的模块进去。包含卖家的名称和头像,可以点进卖家的详情页,也不用太着急,午饭前上线就行。”

于是前后端坐在一起开始商量,前端弱弱的说:“能不能改一下你的接口,把产品不要的都去掉,产品需要的都加上”。

后端心里说,你当我傻啊,于是一边砸吧嘴一边赶忙说道:“这样改风险太大,好多数据都不在一个表,我不好查。这样,详情页那个接口我就不改了,你不显示不就完了嘛,万一哪天产品那小子的小子再想起来加上,咱俩还得忙活。库存再给你一个接口,卖家信息再给你一个接口,完美,就这么定了。”

前端还想再说什么,可后端的背影已经随着产品越走越远。

就在前端绝望之时,霹雳一声震天响,graphql闪亮登场。

在graphql模式下,假设我们的服务端部分已经部署完成,前端使用vue框架,那么前端部分的请求就可以简化为:

  apollo: {
goods: {
query() {
return gql`{
goods(infoId:"${this.infoId}"){
title
content
price
image
}
}`
}
},
store: {
query() {
return gql`{
store(infoId:"${this.infoId}"){
store
}
}`
}
},
seller: {
query() {
return gql`{
seller(infoId:"${this.infoId}"){
name
age
}
}`
}
}
}

可以看到graphql为我们定义了一种类似sql的查询语言,而这种查询语言是用于api的。和之前的数据请求处理不同,在这里,我们只要定义好需要的数据,其他的不再关心,我们就可以按需索取需要的数据。这对于我们的开发提供了更大的自由与便利,只要数据支持,我们就可以摆脱对于服务端接口的依赖,提高生产效率,赢得自由,完成前端的逆袭。

前后端实践

讲完了故事,我们开始讲一些实际的干货。

对于graphql,网上已经有很多实践经验,以下部分是在参考完成实践经验并自我实践后给出的总结归纳。

服务端

服务端的技术选型,我们使用了eggjs框架,配合egg-graphqlegg-graphql插件完成。

1.安装依赖包
$ npm install --save egg-graphql
2.开启插件
// config/plugin.js
exports.graphql = {
enable: true,
package: 'egg-graphql',
};
//开启 cros 跨域访问
exports.cors = {
enable: true,
package: 'egg-cors'
}
3.配置graphql路由和跨域
//config/config.default.js
// graphql路由
config.graphql = {
router: '/graphql',
// 是否加载到 app 上,默认开启
app: true,
// 是否加载到 agent 上,默认关闭
agent: false,
// 是否加载开发者工具 graphiql, 默认开启。路由同 router 字段。使用浏览器打开该可见。
graphiql: true,
// graphQL 路由前的拦截器
onPreGraphQL: function*(ctx) {},
// 开发工具 graphiQL 路由前的拦截器,建议用于做权限操作(如只提供开发者使用)
onPreGraphiQL: function*(ctx) {},
}
// cors跨域
config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
}
4.开启graphql中间件
//config/config.default.js
exports.middleware = [ 'graphql' ];

项目配置告于段落。

5.编写业务员代码

下面开始写代码。

目录结构如下:


├── app
│ ├── graphql //graphql 代码,所有和graphql相关的代码都在这里,已经在前面做好了配置
│ │ └── common //通用类型定义,graphql有一套自己的系统类型,除此之外还可以自定义
│ │ | |── scalars //自定义类型定义
│ │ | | └── date.js // 日期类型实现
│ │ | └── resolver.js //合并所有全局类型定义
│ │ | └── schema.graphql // schema 定义
│ │ └──goods // 商品详情的graphql模型
│ │ └── connector.js //连接数据服务
│ │ └── resolver.js //类型实现,和goods中schema.graphql定义的模型相对应,是其具体的实现
│ │ └── schema.graphql //schema 定义,在这里定义商品详情数据对象
│ │ └──store // 库存的graphql模型
│ │ └── connector.js //连接数据服务
│ │ └── resolver.js //类型实现
│ │ └── schema.graphql //schema 定义,在这里定义商品详情数据对象
│ │ └──seller // 卖家信息的graphql模型
│ │ └── connector.js //连接数据服务
│ │ └── resolver.js //类型实现
│ │ └── schema.graphql //schema 定义,在这里定义商品详情数据对象
│ │ └──query // 所有的查询都会经过这里,这里是一个总的入口
│ │ └── schema.graphql //schema 定义
│ ├── service
│ │ └── goods.js //商品详情的具体实现
│ │ └── store.js //库存的具体业务逻辑
│ │ └── seller.js //卖家信息的具体业务逻辑
│ └── router.js

app/graphql/query/schema.graphql是整个graphql查询的总入口,所有需要查询的对象都要在这里定义。它的定义形式如下:

#定义查询对象,在graphql里的注释使用#号
type Query {
goods(
  #查询条件,相当于接口的入参商品id
  infoId: ID!
):Goods #Goods是在app/graphql/goods/schema.graphql中定义的商品详情
}

在总入口中涉及到的查询对象,都需要在graphql文件夹下建立相应的文件夹,如上文中提到的goods,就在app/graphql文件夹中存在相应的goods文件夹。goods文件夹包含三个部分:schema.graphql,resolve.js和connector.js。

schema.graphql中需要定义总入口中提及的Goods对象:

# 商品
type Goods {
# 流水号
infoId: ID!
# 商品标题
title:String!,
# 商品内容
content:'String!,
#商品特点
special:'String!,
#商品价格
price:'nt!,
#商品图片
image:'String!,
}

graphql自带一组默认标量类型,包括Int,Float,String,Boolean,ID。在定义字段时需要注明类型,这也是graphql的特点之一,是支持强类型的。如果非空,就在类型后面跟上一个!号。graphql还包括枚举类型,列表和自定义类型,具体可以查看相关文档。

resolve.js是数据类型的具体实现,依赖connector.js完成:

'use strict'
module.exports = {
Query: {
goods(root, {infoId}, ctx) {
return ctx.connector.goods.fetchById(infoId)
}
}

connector.js是连接数据的具体实现,可以使用dataloader来降低数据访问频次,提高性能:

'use strict'
//引入dataloader,是由facebook推出,能大幅降低数据库的访问频次,经常在Graphql场景中使用
const DataLoader = require('dataloader')
class GoodsConnector {
constructor(ctx) {
this.ctx = ctx
this.loader = new DataLoader(id=>this.fetch(id))
}
fetch(id) {
const goods = this.ctx.service.goods
return new Promise(function(resolve, reject) {
const goodsInfo = goods.getInfoById(id)
resolve([goodsInfo]) //注意这里需要返回数组形式
})
}
fetchById(id) {
return this.loader.load(id)
}
}
module.exports = GoodsConnector

上面代码中涉及的this.ctx.service.goods就是app/service文件夹下的goods.js文件导出的方法对象,也就是获取数据的具体业务逻辑:

const Service = require('egg').Service
const {createAPI} = require('../util/request')//实现的http请求
class GoodsService extends Service {
// 获取商品详情
async getInfoById(infoId) {
const result = await createAPI(this, 'example/getInfoById', 'get', {infoId})
return result
}
}
module.exports = GoodsService

获取数据可以用你能实现的任何方式,可以直接从数据库获取,也可以用http从现有的接口获取。

这样一个使用egg框架实现的graphql服务就完成了。

下面说一下前端。

前端

我们会使用vue配合Apollo完成前端搭建。

1 安装依赖包
npm install --save vue-apollo apollo-client
2.引用apollo
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'
3.配置链接
const httpLink = new HttpLink({
// 需要配置一个绝对路径
uri: 'http://exzample.com/graphql',
})
4.创建ApolloClient实例和PROVIDER
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
connectToDevTools: true,
})
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
4.在vue中引入使用
Vue.use(VueApollo);
5.根实例引用
    var vm = new Vue({
el: '#app',
provide: apolloProvider.provide(),
router,
components: {
app: App
},
render: createEle => createEle('app')
})
6.使用
<script>
import gql from "graphql-tag";
export default {
data() {
return {
goods:{},
infoId:123123
};
},
apollo: {
goods: {
query() {
return gql`{
goods(infoId:"${this.infoId}"){
title
content
price
image
}
}`
}
},
}
};
</script>

展望

graphql对于目前接口数量多,难维护,扩展成本高,数据格式不可预知,文档难维护等问题给出了一个相对完善的方案,相信在未来,它将是我们工作中不可或缺的一部分。

GraphQL-前端开发的利剑与桥梁的更多相关文章

  1. 掌握这两个技术点,你可以玩转AppCan前端开发

    “AppCan的前端开发其实非常简单,只要掌握两方面的技术即可.一方面是会使用栅格布局完成UI的界面排版,另外一方面就是使用AppCan MVVM模型来完成整个页面构造和用户操作逻辑.” 在2016A ...

  2. webstorm+nodejs+JetBrains IDE Support+chrome打造前端开发神器

    #webstorm+nodejs+JetBrains IDE Support+chrome打造前端开发神器 -- 工欲善其事 必先利其器 ##各工具介绍 `webstorm`是**JetBrains* ...

  3. 前端开发:如何写一手漂亮的 Vue

    前几日听到一句生猛与激励并存,可怕与尴尬同在,最无奈也无解的话:"90后,你的中年危机已经杀到".这令我很受触动.显然,这有些夸张了,但就目前这日复一日的庸碌下去,眨眼的功夫,那情 ...

  4. 十分钟看懂,未来Web前端开发最新趋势

    首先,展望未来趋势我们就要弄懂过去的一年,也就是18年,web前端开发的重要新闻.重要事件和JavaScript的各种流行框架.模式发展趋势. 我们来快速回顾一下. NPM热门前端框架下载 先来看最热 ...

  5. web前端开发-博客目录

    web前端开发是一个新的领域,知识连接范围广,处于设计与后端数据交互的桥梁,并且现在很多web前端相关语言标准,框架库都在高速发展.在学习过程中也常常处于烦躁与迷茫,有时候一直在想如何能够使自己更加系 ...

  6. 前端开发 JavaScript 干货知识点汇总

    很多初学的朋友经常问我,前端JavaScript都需要学习哪些东西呀?哪些是JavaScript的重点知识啊? 其实做前端开发工程师,所有的知识点都是我们学习必备的东西,只有扎实的技术基础才是高薪的关 ...

  7. VS Code 成主宰、Vue 备受热捧!2019 前端开发趋势必读

    前端在生产和开发中占据着越来越重要的地位,PC 端.手机端.桌面端.智能手表端等等设备都离不开前端的身影.本文将围绕框架.编程语言.工具.React.Vue 等方面,全面回顾 2019 年前端与 We ...

  8. 前端开发神器 VSCode 使用总结

    VSCode 是微软出品的,基于 Electron 和 TypeScript 的,集成了 git 版本管理和命令行终端,而且开源稳定,插件丰富,再搭配一款 Chrome 浏览器,可以说是前端开发神器了 ...

  9. 面向前端开发人员的VSCode自动化插件

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://blog.bitsrc.io/vscode-automations-for-fro ...

随机推荐

  1. Python数据可视化之Matplotlib实现各种图表

    数据分析就是将数据以各种图表的形式展现给领导,供领导做决策用,因此熟练掌握饼图.柱状图.线图等图表制作是一个数据分析师必备的技能.Python有两个比较出色的图表制作框架,分别是Matplotlib和 ...

  2. VS挂机移动鼠标代码

    #include <time.h> #include <stdio.h> #include <Windows.h> HANDLE ghMutex; //////// ...

  3. Docker 学习9 Docker私有registry

    一.docker registry分类 二.安装docker-hub提供的registry 1.安装 [root@localhost yum.repos.d]# yum install -y dock ...

  4. ubuntu制作离线包

    一.应用场景a.当我们需要在多台电脑安装同一个软件,并且这个软件很大,下载需要很长时间b.需要安装软件的ubuntu不能上网二.离线安装包的制作2.1.通过如下指令下载XXXX软件所需要的deb包,首 ...

  5. 关于Selenium3+python3.6自动化测试中iframe切换

    本篇内容主要表述以下几个问题: 1.iframe 这个是什么? 2.定位iframe 标签时遇到的几个报错总结. 3.显示等待与隐示等待的原理与优缺点. 4.无name,ID可变情况下的处理方式 5. ...

  6. Codeforces 1153D Serval and Rooted Tree (简单树形DP)

    <题目链接> 题目大意: Serval拥有的有根树有n个节点,节点1是根. Serval会将一些数字写入树的所有节点.但是,有一些限制.除叶子之外的每个节点都有一个写入操作的最大值或最小值 ...

  7. BZOJ.2054.疯狂的馒头(并查集)

    BZOJ 倒序处理,就是并查集傻题了.. 并查集就是确定下一个未染色位置的,直接跳到那个位置染.然而我越想越麻烦=-= 以为有线性的做法,发现还是要并查集.. 数据随机线段树也能过去. //18400 ...

  8. IntelliJ IDEA最新破解版2018.3.1(附2018.2.2 完美破解教程)

    2018.3.1最新版破解 1.官网下载IDEA 2018.3.1的商业版本点我去下载 2.破解jar下载:JetbrainsIdesCrack-3.4-release-enc.jar点我去下载 3. ...

  9. 在浏览器输入URL时发生了什么

    浏览器器检查cache,如果请求对象已经缓存并且是最新的,执行第9步. 浏览器询问操作系统,请求服务器的IP地址 操作系统进行DNS查找,然后告诉浏览器服务器的IP 浏览器和服务器简历一个TCP连接( ...

  10. vue2.0 如何自定义组件(vue组件的封装)

    一.前言 之前的博客聊过 vue2.0和react的技术选型:聊过vue的axios封装和vuex使用.今天简单聊聊 vue 组件的封装. vue 的ui框架现在是很多的,但是鉴于移动设备的复杂性,兼 ...