百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

GraphQL-前端进阶的利剑与桥梁(guns前端)

ccwgpt 2024-10-12 02:42 21 浏览 0 评论

作者 | 卢铭

基本概念

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

相关推荐

详解DNFSB2毒王的各种改动以及大概的加点框架

首先附上改动部分,然后逐项分析第一个,毒攻掌握技能意思是力量智力差距超过15%的话差距会被强行缩小到15%,差距不到15%则无效。举例:2000力量,1650智力,2000*0.85=1700,则智力...

通篇干货!纵观 PolarDB-X 并行计算框架

作者:玄弟七锋PolarDB-X面向HTAP的混合执行器一文详细说明了PolarDB-X执行器设计的初衷,其初衷一直是致力于为PolarDB-X注入并行计算的能力,兼顾TP和AP场景,逐渐...

字节新推理模型逆袭DeepSeek,200B参数战胜671B,豆包史诗级加强

梦晨发自凹非寺量子位|公众号QbitAI字节最新深度思考模型,在数学、代码等多项推理任务中超过DeepSeek-R1了?而且参数规模更小。同样是MoE架构,字节新模型Seed-Thinkin...

阿里智能化研发起飞!RTP-LLM 实现 Cursor AI 1000 token/s 推理技术揭秘

作者|赵骁勇阿里巴巴智能引擎事业部审校|刘侃,KittyRTP-LLM是阿里巴巴大模型预测团队开发的高性能LLM推理加速引擎。它在阿里巴巴集团内广泛应用,支撑着淘宝、天猫、高德、饿...

多功能高校校园小程序/校园生活娱乐社交管理小程序/校园系统源码

校园系统通常是为学校、学生和教职工提供便捷的数字化管理工具。综合性社交大学校园小程序源码:同城校园小程序-大学校园圈子创业分享,校园趣事,同校跑腿交友综合性论坛。小程序系统基于TP6+Uni-app...

婚恋交友系统nuiAPP前端解决上传视频模糊的问题

婚恋交友系统-打造您的专属婚恋交友平台系统基于TP6+Uni-app框架开发;客户移动端采用uni-app开发,管理后台TH6开发支持微信公众号端、微信小程序端、H5端、PC端多端账号同步,可快速打包...

已节省数百万GPU小时!字节再砍MoE训练成本,核心代码全开源

COMET团队投稿量子位|公众号QbitAI字节对MoE模型训练成本再砍一刀,成本可节省40%!刚刚,豆包大模型团队在GitHub上开源了叫做COMET的MoE优化技术。COMET已应用于字节...

通用电气完成XA102发动机详细设计审查 将为第六代战斗机提供动力

2025年2月19日,美国通用电气航空航天公司(隶属于通用电气公司)宣布,已经完成了“下一代自适应推进系统”(NGAP)计划下提供的XA102自适应变循环发动机的详细设计审查阶段。XA102是通用电气...

tpxm-19双相钢材质(双相钢f60材质)

TPXM-19双相钢是一种特殊的钢材,其独特的化学成分、机械性能以及广泛的应用场景使其在各行业中占有独特的地位。以下是对TPXM-19双相钢的详细介绍。**化学成分**TPXM-19双相钢的主要化学成...

thinkphp6里怎么给layui数据表格输送数据接口

layui官网已经下架了,但是产品还是可以使用。今天一个朋友问我怎么给layui数据表格发送数据接口,当然他是学前端的,后端不怎么懂,自学了tp框架问我怎么调用。其实官方文档上就有相应的数据格式,js...

完美可用的全媒体广告精准营销服务平台PHP源码

今天测试了一套php开发的企业网站展示平台,还是非常不错的,下面来给大家说一下这套系统。1、系统架构这是一套基于ThinkPHP框架开发的HTML5响应式全媒体广告精准营销服务平台PHP源码。现在基于...

一对一源码开发,九大方面完善基础架构

以往的直播大多数都是一对多进行直播社交,弊端在于不能满足到每个用户的需求,会降低软件的体验感。伴随着用户需求量的增加,一对一直播源码开始出现。一个完整的一对一直播流程即主播发起直播→观看进入房间观看→...

Int J Biol Macromol .|交联酶聚集体在分级共价有机骨架上的固定化:用于卤代醇不对称合成的高稳定酶纳米反应器

大家好,今天推送的文章发表在InternationalJournalofBiologicalMacromolecules上的“Immobilizationofcross-linkeden...

【推荐】一款开源免费的 ChatGPT 聊天管理系统,支持PC、H5等多端

如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍GPTCMS是一款开源且免费(基于GPL-3.0协议开源)的ChatGPT聊天管理系统,它基于先进的GPT...

高性能计算(HPC)分布式训练:训练框架、混合精度、计算图优化

在深度学习模型愈发庞大的今天,分布式训练、高效计算和资源优化已成为AI开发者的必修课。本文将从数据并行vs模型并行、主流训练框架(如PyTorchDDP、DeepSpeed)、混合精度训练(...

取消回复欢迎 发表评论: