qjson从接口里取数据_如何使用 GraphQL 来进行增删改查和数据订阅推送?

本文首先介绍了 GraphQL,再通过 MongoDB + graphql + graph-pack 的组合实战应用 GraphQL,详细阐述如何使用 GraphQL 来进行增删改查和数据订阅推送,并附有使用示例,边用边学印象深刻~

如果希望将 GraphQL 应用到前后端分离的生产环境,请期待后续文章。

本文实例代码:Github

0. 什么是 GraphQL

GraphQL 是一种面向数据的 API 查询风格。

传统的 API 拿到的是前后端约定好的数据格式,GraphQL 对 API 中的数据提供了一套易于理解的完整描述,客户端能够准确地获得它需要的数据,没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

1. 概述

前端的开发随着 SPA 框架全面普及,组件化开发也随之成为大势所趋,各个组件分别管理着各自的状态,组件化给前端仔带来便利的同时也带来了一些烦恼。比如,组件需要负责把异步请求的状态分发给子组件或通知给父组件,这个过程中,由组件间通信带来的结构复杂度、来源不明的数据源、不知从何订阅的数据响应会使得数据流变得杂乱无章,也使得代码可读性变差,以及可维护性的降低,为以后项目的迭代带来极大困难。

试想一下你都开发完了,产品告诉你要大改一番,从接口到组件结构都得改,后端也骂骂咧咧不愿配合让你从好几个 API 里取数据自己组合,这酸爽

在一些产品链复杂的场景,后端需要提供对应 WebApp、WebPC、APP、小程序、快应用等各端 API,此时 API 的粒度大小就显得格外重要,粗粒度会导致移动端不必要的流量损耗,细粒度则会造成函数爆炸 (Function Explosion);在此情景下 Facebook 的工程师于 2015 年开源了GraphQL 规范,让前端自己描述自己希望的数据形式,服务端则返回前端所描述的数据结构。

简单使用可以参照下面这个图:

ec358806c8e42b2e9d4b768e4d0e88e8.gif

比如前端希望返回一个 ID 为 233 的用户的名称和性别,并查找这个用户的前十个雇员的名字和 Email,再找到这个人父亲的电话,和这个父亲的狗的名字(别问我为什么有这么奇怪的查找 ),那么我们可以通过 GraphQL 的一次 query 拿到全部信息,无需从好几个异步 API 里面来回找:

query { user (id : "233") { name gender employee (first: 10) { name email } father { telephone dog { name } } }}

返回的数据格式则刚好是前端提供的数据格式,不多不少,是不是心动了

2. 几个重要概念

这里先介绍几个对理解 GraphQL 比较重要的概念,其他类似于指令、联合类型、内联片段等更复杂的用法,参考 GraphQL 官网文档 ~

2.1 操作类型 Operation Type

GraphQL 的操作类型可以是 query、 mutation 或 subscription,描述客户端希望进行什么样的操作

  1. query 查询:获取数据,比如查找,CRUD 中的 R
  2. mutation 变更:对数据进行变更,比如增加、删除、修改,CRUD 中的 CUD
  3. substription 订阅:当数据发生更改,进行消息推送

这些操作类型都将在后文实际用到,比如这里进行一个查询操作

query { user { id }}

2.2 对象类型和标量类型 Object Type & Scalar Type

如果一个 GraphQL 服务接受到了一个 query,那么这个 query 将从 RootQuery 开始查找,找到对象类型(Object Type)时则使用它的解析函数 Resolver 来获取内容,如果返回的是对象类型则继续使用解析函数获取内容,如果返回的是标量类型(Scalar Type)则结束获取,直到找到最后一个标量类型。

  1. 对象类型:用户在 schema 中定义的 type
  2. 标量类型:GraphQL 中内置有一些标量类型 String、 Int、 Float、 Boolean、 ID,用户也可以定义自己的标量类型

比如在 Schema 中声明

type User { name: String! age: Int}

这个 User 对象类型有两个字段,name 字段是一个为 String 的非空标量,age 字段为一个 Int 的可空标量。

2.3 模式 Schema

如果你用过 MongoOSE,那你应该对 Schema 这个概念很熟悉,翻译过来是『模式』。

它定义了字段的类型、数据的结构,描述了接口数据请求的规则,当我们进行一些错误的查询的时候 GraphQL 引擎会负责告诉我们哪里有问题,和详细的错误信息,对开发调试十分友好。

Schema 使用一个简单的强类型模式语法,称为模式描述语言(Schema Definition Language, SDL),我们可以用一个真实的例子来展示一下一个真实的 Schema 文件是怎么用 SDL 编写的:

# src/schema.graphql# Query 入口type Query { hello: String users: [User]! user(id: String): [User]!}# Mutation 入口type Mutation { createUser(id: ID!, name: String!, email: String!, age: Int,gender: Gender): User! updateUser(id: ID!, name: String, email: String, age: Int, gender: Gender): User! deleteUser(id: ID!): User}# Subscription 入口type Subscription { subsUser(id: ID!): User}type User implements UserInterface { id: ID! name: String! age: Int gender: Gender email: String!}# 枚举类型enum Gender { MAN WOMAN}# 接口类型interface UserInterface { id: ID! name: String! age: Int gender: Gender}

这个简单的 Schema 文件从 Query、Mutation、Subscription 入口开始定义了各个对象类型或标量类型,这些字段的类型也可能是其他的对象类型或标量类型,组成一个树形的结构,而用户在向服务端发送请求的时候,沿着这个树选择一个或多个分支就可以获取多组信息。

注意:在 Query 查询字段时,是并行执行的,而在 Mutation 变更的时候,是线性执行,一个接着一个,防止同时变更带来的竞态问题,比如说我们在一个请求中发送了两个 Mutation,那么前一个将始终在后一个之前执行。

2.4 解析函数 Resolver

前端请求信息到达后端之后,需要由解析函数 Resolver 来提供数据,比如这样一个 Query:

query { hello}

那么同名的解析函数应该是这样的

Query: { hello (parent, args, context, info) { return ... }}

解析函数接受四个参数,分别为

  1. parent:当前上一个解析函数的返回值
  2. args:查询中传入的参数
  3. context:提供给所有解析器的上下文信息
  4. info:一个保存与当前查询相关的字段特定信息以及 schema 详细信息的值

解析函数的返回值可以是一个具体的值,也可以是 Promise 或 Promise 数组。

一些常用的解决方案如 Apollo 可以帮省略一些简单的解析函数,比如一个字段没有提供对应的解析函数时,会从上层返回对象中读取和返回与这个字段同名的属性。

2.5 请求格式

GraphQL 最常见的是通过 HTTP 来发送请求,那么如何通过 HTTP 来进行 GraphQL 通信呢

举个栗子,如何通过 Get/Post 方式来执行下面的 GraphQL 查询呢

query { me { name }}

Get 是将请求内容放在 URL 中,Post 是在 content-type:application/json 情况下,将 JSON 格式的内容放在请求体里

# Get 方式http://myapi/graphql?query={me{name}}# Post 方式的请求体{ "query": "...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值