关于graphql:优化开发流程顶级-GraphQL-工具推荐

GraphQL 工具本文章,会列举一些好用的 GraphQL 工具,他们能够大大晋升你在开发中应用 GraphQL 的效率哦! Prisma你能够这么了解,Prisma 是一个 ORM 的库,让你应用 GraphQL 查问时,能够应用对象的模式去查问,而不须要应用查问语句去查问,十分不便,而且 Prisma 还领有以下特点: Prisma 反对很多数据库,比方 Mysql、PostgreSQL、MariaDB 等数据库,当前还会反对更多对 Typescript、JavaScript、Go 都有十分好的反对内置了一些 CURD 的性能 RelayRelay 是一个 JavaScript 库,由 Facebook 开发,比拟多的用在 React 开发中,在 React 开发时,能够应用 Relay 去对 GraphQL 进行增删改查,十分不便。 Relay 具备三个模块: Compiler:编译器,负责剖析、验证、优化Runtime:GraphQL 的运行环境Relay/React:Relay 与 React 集成在一起 Apifox依据官网的介绍,Apifox 是这样的一款工具 集成了API 文档、API 调试、API Mock、API 自动化测试 API 一体化合作平台领有更先进的 API 设计/开发/测试工具Apifox = Postman + Swagger + Mock + JMeter我用了一圈下来,发现 Apifox 的性能的确很多 反对接口文档、在线接口文档分享反对本地 Mock、云端 Mock 性能反对 自动化测试,包含测试用例、测试套件性能反对中文显示,且收费应用反对可视化校验、可视化数据库连贯领有 IDEA 插件 Apifox Helper领有命令行工具 apifox-cli,能够应用命令行运行测试用例 ...

August 23, 2023 · 1 min · jiezi

关于graphql:从零开始学习-GraphQL入门指南和教程

意识 GraphQL前段时间,GraphQL 呈现并掀起了一阵热潮。然而 GraphQL 跟 REST 是两种不同的货色,所以也须要肯定的学习老本,导致大部分人都没有抉择去学习它,明天就带大家简略过一遍 GraphQL 吧,心愿大家能有所播种。 常识扩大:GraphQL 和 REST 比照 GraphQL 好在哪?首先来说说 GraphQL 到底好在哪: GraphQL 速度快并且稳固GraphQL 能够获取更多的资源GraphQL 是单端点查问GraphQL 的可持续性十分杰出GraphQL 具备向下兼容的个性GraphQL 应用场景GraphQL 的按需查问十分实用,试想一下,你们在开发一个十分大型的网站的时候,一个首页就得申请很多个接口了,比方: 轮播图接口Tag 接口List 接口在下面的例子里,一个首页就得申请三个以上的接口了,浏览器并发数太多的话,会大大影响用户的应用体验。 那如果应用 GraphQL 去查问呢,就只须要一个接口就完事了,也就是一个申请就能够查问很多个申请所须要的数据,那天然缩小了并发数。 GraphQL 教程GraphQL 其实不难,无非就是传个不同的 query语句 到后端,接管不同的 JSON 罢了。 query 查问比方我当初要设计一个学生治理平台,我想查问学生列表,我应该传什么参数呢? 剖析一下下面的语句: query:操作类型getStudents:操作函数名students:是后端定义好的接口id,name,age:指的是咱们须要查问的字段这样查问,返回的数据为: 察看下面的数据,使咱们想要的数据,并且只返回咱们须要查问的字段。 传参查问咱们刚刚说了 getStudents 是 函数名,那既然是函数,必定是能够传参的,比方,咱们只须要查问 id 为 1 的学生,咱们能够这么传: query variables 这样就能查到咱们想要的数据了。 mutation 批改后面讲的是 query 语句,咱们试一下 mutation 语句,他能够对数据进行批改、新增。 比方咱们想要新增一个学生,咱们能够这么写: 调试 GraphQL 接口步骤咱们写完 GraphQL 接口之后,咱们须要应用 API 工具对 GraphQL 接口进行调试。 ...

April 17, 2023 · 1 min · jiezi

关于graphql:独立产品灵感周刊-DecoHack-038-纽约市-90-年代的街景长什么样

本周刊记录乏味好玩的独立产品设计开发相干内容,每周公布,往期内容同样精彩,感兴趣的搭档能够点击订阅我的周刊。为保障每期都能收到,倡议邮件订阅。欢送通过 Twitter 私信举荐或投稿。产品举荐1940s.nyc - 这个网站能够看到 90 年代纽约市的街景照片,太多照片了,根本齐全笼罩,还有另外一个我的项目是看 80 年代时候照片的。 Madsounds - 应用 Spotify 听歌的敌人们能够关上这个网站,受权登陆之后就会主动创立一个每日发现的歌单,关上 APP 就能够间接看到,相似 原本就有的每周新发现歌单,这个第三方的插件还是挺有意思的,第一次看到还有这种操作。 screen.studio - 这个屏幕录制软件做的很粗劣,鼠标点击动效,静止含糊,产品设计的很难看,交互也很不错,产品适宜用来录制完分享社交平台,例如Twitter 演示等场景,这个软件只实用于 macOS,反对 120FPS 的 4K 录制。89 美元买断制,一个许可证,容许最多三台设施装置和应用。 Letterloop - 这个产品能够给你的家人、敌人或者团队创立一个私密的 Newsletter,每个人都能提出和答复乏味的问题,用来分享本人的生存等,用来拉近家人和敌人之间的间隔,不得不说当初即时通信工具十分发达,信息过于爆炸,能用这种形式放弃短暂然而高效的社交形式还是很有创意的,能够看一下官网给出的一些应用案例。产品付费,每月 50 美元。 Paper Airplane Designs - 这个网站收集了很多纸飞机的设计,很乏味啊。 正则表达式游戏 - 这是个益智游戏,能够测试你写正则表达式的技能。 signlearner - 这是一个浏览器插件,用来学习手语,装置这个插件之后,会在你浏览的网站上随机呈现一些词语,悬浮下来就会呈现一个视频教这个词语的手语如何表白。做的很不错。小众然而有价值的产品。 开源我的项目Book Keeping - 九快记账是一款开源的记账类的工具软件,次要给集体和开店店主应用,反对手机和电脑,手机(包含安卓和iOS)通过装置APP应用,电脑通过浏览器应用。 ToastFish - 这是一个利用 Windows 告诉栏背单词的软件。能够让你在下班、上课等顽劣环境下平安荫蔽的背单词。能够查看背诵记录,能够将背诵记录导入,从新背诵,自定义 Excel 内容等性能。软件齐全开源且收费。 GitHub 推出两种新字体:Mona Sans 和 Hubot Sans - 来自 GitHub 的两种可变开源字体。 lenis - 这是一个前端框架,用来做平滑滚动成果,那些很丝滑的网页动效看上去就很业余。开源我的项目。 Slimicon - 这是一个收费开源的图标库。100多个圆角线形图标。 ...

November 21, 2022 · 1 min · jiezi

关于graphql:独立产品灵感周刊-DecoHack-032-这些渠道可以推广你的新产品

本周刊记录乏味好玩的独立产品设计开发相干内容,每周公布,往期内容同样精彩,感兴趣的搭档能够点击订阅我的周刊。为保障每期都能收到,倡议邮件订阅。欢送通过 Twitter 私信举荐或投稿。产品举荐Manhole - 这个网站太有意思了,收录了十分多全世界各地乏味的井盖!还能看这个井盖具体在什么中央。第一次感觉井盖还能够有这么多的设计!另外强烈推荐看一下这个 Reddit 频道:r/manholeporn/。日本的井盖设计真多,又可恶又难看,另外这个网站还开发了 APP 能够上传你看到的乏味的井盖。 ezcv - 这是一个在线制作简历的网站,十分简洁好用,默认了一些罕用的排版,用最简略的款式展现你的简历内容。 TakeAscreen - 这是一个截图优化编辑的工具,浏览器插件,能够疾速应用标注,抉择款式等操作,还是很不便的。付费产品,价格不高。 Who is in space - 这个网站显示当初有多少人在太空,有多少个厕所在太空,有多少被动摸索其余星球的机器人。 The Deep Sea - 这个网站也很有意思,能够很直观地看海底多深的中央有什么用的生物。 Post-Secret Voicemail - 这个网站能够公布匿名的语音,下面有很多人的留言,很多都在讲述本人比拟悲伤的人生。 Flick Focus - 这个网站能够用来治理你观看电影电视剧等的数据,而且这个网站上找电影的体验比 IMDb 好用多了,能够查看乏味的统计数据,例如评分最高和观看次数最多的导演、演员、平均水平。评级公布年份及更多。这个网站应用 TMDb 的 API 开发。不能间接在下面看电影。另外举荐试试 Trakt.tv 治理你的观看数据。 Figma 主题切换插件 - 这是 @leadream4 开发的又一款优良的插件,感兴趣能够看看 视频介绍,能够试用 3 天,当初七折促销中。次要性能:增加本地或近程款式为主题,疾速切换主题,从一个主题复制款式生成新主题,分享主题给共事/敌人。这里购买。 开源我的项目hackers mind map - 适宜开发者用的思维导图工具,次要用键盘操作。太过于极客,普通用户就别用了。 轻易看看The Hustlers - 这个 Newsletter 次要整顿一些人的副业以及支出等等,曾经出了几期了,做的还不错。Starter Story - 这个 Newsletter 整顿了很多守业新我的项目,有 3806 个案例钻研,波及为数千名建设业务的创始人。一些适宜 SwiftUI 初学者的教程 - 对 SwiftUI 感兴趣的敌人能够看看。东坡肘子 @fatbobman 整顿的教程,针对技术根底较低的学习者( 甚至能够零根底学习 )。史蒂夫乔布斯档案 - Steve Jobs Archive 这个网站整顿了乔布斯的次要思维。Kalënder 2023 - 明年的日历曾经有人设计了,没记错的话当初曾经有余100天往年就完结了。这个能够收费下载而后打印,设计的还不错。 ...

September 26, 2022 · 1 min · jiezi

关于graphql:狩猎者夹子机器人系统开发逻辑Python框架

The blockchain system consists of (Wey》StPv888)numerous nodes, which are similar to a Tai When a computer works independently, each node will participate in the competition when accounting is required. The system will select the most appropriate node for accounting within a period of time, and this node will record the recent data changes in the data block. After the recording is completed, the node will send this data block to other nodes. Other nodes will first verify the data. If the data is correct, This data block will also be put into its own account book, so all nodes in the system have exactly the same data block, that is, the account book. ...

May 31, 2022 · 1 min · jiezi

关于graphql:GraphQL-碰撞-Apache-APISIX提升-API-领域的安全与性能

本文介绍了 Apache APISIX 和 GraphQL 的个性,以及如何应用 API 网关 Apache APISIX 代理 GraphQL 申请,并提出解决理论场景痛点的计划。 背景信息GraphQL 是一个开源的、面向 API 而发明进去的数据查问操作语言以及相应的运行环境。最后由Facebook 于 2012 年外部开发,2015 年公开公布。2018 年 11 月 7 日,Facebook 将 GraphQL 我的项目转移到新成立的 GraphQL 基金会。 您能够把 GraphQL 类比为 SQL 查问语句来了解,与 SQL 查问语句相比,GraphQL 对 API 中的数据提供了一套易于了解的残缺形容,让客户端可能通过自定义的形容来精确取得其所须要的数据。这也让 API 可能从容面对日益简单的接口倒退,并防止最终成为一个令人望而却步的简单接口。 Apache APISIX 作为云原生网关,在设计之初就曾经具备辨认 GraphQL 语法的匹配能力。通过对申请中携带的 GraphQL 语句进行高效匹配,筛除异样流量,进一步保障安全性和进步零碎性能。 场景解析咱们正处于大数据大流量的时代,Apache APISIX 和 GraphQL 能够通过联合的形式,造成共赢的场面。接下来举一个场景具体阐明。 本文将会探讨微服务架构场景下的 Apache APISIX 和 GraphQL 的理论利用。 理论场景中遇到的问题在我的项目进行到前期时,往往会呈现业务复杂化、团队人员流动性低等问题,而微服务架构曾经成为解决这类问题的常见解决方案。在微服务架构中,GraphQL 暴露出的接口分为分散式和集中式两种,然而只有集中式接口设计才可能最大化体现 GraphQL 的劣势,然而在集中式接口设计中,所有的微服务对外裸露的是同一个接口,因而解决流量的路由就不能简略地依据 URL 进行转发,而是应该依据申请中蕴含的不同字段进行转发。 因为 NGINX 解决申请时仅会解决 URL 以及一些参数,然而只有解析申请参数中的查问信息才能够晓得客户端拜访的资源,从而进行路由转发,因而这种路由转发形式通过传统的 NGINX 是无奈实现的。在理论利用场景中,将 GraphQL 接口间接对外裸露十分危险,因而须要一个业余的高性能 API 网关爱护 GraphQL 的接口。 ...

March 8, 2022 · 3 min · jiezi

关于graphql:graphQL-在catch中获取展示完整的错误信息

不看废话版:err.networkError.result.errors(list) this.$apollo.mutate({ mutation: ***,//mutation name variables:{ *** // 一些参数 }}).then(res => { //接口200时解决,,,}).catch((err)=>{ if(err&& err.networkError&& err.networkError.result&&err.networkError.result.errors&&err.networkError.result.errors[0]){ let errors = err.networkError.result.errors[0]; let mes = errors.message; alert(mes)//或者其余解决 }})

February 8, 2022 · 1 min · jiezi

关于graphql:GraphQL-快速入门5GraphQL-示例

【注】本文译自:GraphQL - Quick Guide (tutorialspoint.com)    在本章中,咱们将创立一个简略的 API,它返回一条问候音讯 HelloWorld,并应用 GraphiQL 拜访它。 示例    本示例基于 NodeJS、Express 和 Apollo 服务器。咱们将学习通过以下步骤将所有概念联合起来: 第 1 步:设置 Express    ExpressJS 是一个 Web 利用框架,可帮忙构建网站和 Web 应用程序。在这个例子中,咱们将在 Express 框架之上构建一个 GraphQL API。    下一步是创立文件夹 hello-world-server 并从终端导航到同一文件夹。增加 package.json,并为包命名。因为此包仅在外部应用,咱们能够将其申明为公有。 { "name": "hello-world-server", "private": true}    装置 Express 服务器的依赖项,如下所示:C:\Users\Admin\hello-world-server>npm install express body-parser cors    body-parser 是一个中间件包,能够帮忙 Express 无效地解决 HTTP Post 申请。cors 是另一个解决跨源资源共享的中间件包。    在我的项目文件夹中创立 server.js 文件并在其中键入以下内容: const bodyParser = require('body-parser')const cors = require('cors')const express = require('express')const port = process.env.PORT|| 9000const app = express()//register middlewareapp.use(bodyParser.json() , cors())app.listen(port, () => console.log(`server is up and running at ${port}`))    要验证 Express 服务器是否已启动并正在运行,请在终端窗口中执行以下代码:C:\Users\Admin\hello-world-server>node server.js    以下输入显示在服务器控制台中。这表明 express 服务器正在端口 9000 上运行。server is up and running at 9000    如果您关上浏览器并输出 http://localhost:9000 ,您将看到以下屏幕:    要进行服务器,请按 Ctrl + C。 ...

September 29, 2021 · 2 min · jiezi

关于graphql:GraphQL-快速入门3GraphQL-架构

【注】本文译自: GraphQL - Quick Guide (tutorialspoint.com)    GraphQL 是形容 GraphQL 服务器行为的标准。它是一组对于如何解决申请和响应的指南,如反对的协定、服务器能够承受的数据格式、服务器返回的响应格局等。客户端向 GraphQL 收回的申请服务器称为查问。GraphQL 的另一个重要概念是其传输层不可知性。它能够与任何可用的网络协议一起应用,如 TCP、websocket 或任何其余传输层协定。它对数据库也是中立的,因而您能够将它与关系数据库或 NoSQL 数据库一起应用。    能够应用上面列出的三种办法中的任何一种来部署 GraphQL Server: 带有连贯数据库的 GraphQL 服务器集成现有零碎的 GraphQL 服务器混合办法 集成连贯数据库的 GraphQL 服务器    这种架构有一个带有集成数据库的 GraphQL 服务器,通常能够用于新我的项目。收到查问后,服务器读取申请无效负载并从数据库中获取数据。这称为解析查问。返回给客户端的响应遵循官网 GraphQL 标准中指定的格局。    在上图中,GraphQL 服务器和数据库集成在一个节点上。客户端(桌面/挪动)通过 HTTP 与 GraphQL 服务器通信。服务器解决申请,从数据库中获取数据并将其返回给客户端。 GraphQL 服务器集成现有零碎    这种办法对于领有遗留基础设施和不同 API 的公司很有帮忙。GraphQL 可用于对立现有零碎中的微服务、遗留基础设施和第三方 API。    在上图中,GraphQL API 充当客户端和现有零碎之间的接口。客户端应用程序与 GraphQL 服务器通信,后者反过来解析查问。 混合办法    最初,咱们能够将以上两种形式联合起来,搭建一个 GraphQL 服务器。在这种架构中,GraphQL 服务器将解析收到的任何申请。它将从连贯的数据库或集成的 API 中检索数据。这如下图所示:

September 23, 2021 · 1 min · jiezi

关于graphql:GraphQL-快速入门2环境设置

【注】本文节译自:GraphQL - Quick Guide (tutorialspoint.com)    在本章中,咱们将学习 GraphQL 的环境设置。 要执行本教程中的示例,您将须要以下内容: 运行 Linux、macOS 或 Windows 的计算机。网络浏览器,最好是最新版本的 Google Chrome。装置了最新版本的 Node.js。倡议应用最新的 LTS 版本。已装置实用于 VSCode 的扩大 GraphQL 的 Visual Studio Code 或您抉择的任何代码编辑器。如何应用 Nodejs 构建 GraphQL 服务器    咱们将具体介绍应用 Nodejs 构建 GraphQL 服务器的步骤,如下所示: 第 1 步 - 验证节点和 Npm 版本    装置 NodeJs 后,在终端上应用以下命令验证 node 和 npm 的版本: C:\Users\Admin>node -vv8.11.3C:\Users\Admin>npm -v5.6.0第 2 步 - 创立我的项目文件夹并在 VSCode 中关上 我的项目的根文件夹能够命名为 test-app。    依照以下阐明应用 Visual Studio 代码编辑器关上文件夹: C:\Users\Admin>mkdir test-appC:\Users\Admin>cd test-appC:\Users\Admin\test-app>code.第 3 步 - 创立 package.json 并装置依赖项    创立 package.json 文件,该文件将蕴含 GraphQL 服务器应用程序的所有依赖项。 ...

September 13, 2021 · 2 min · jiezi

关于graphql:GraphQL-快速入门1简介

【注】本文节译自:GraphQL - Quick Guide (tutorialspoint.com)     GraphQL 是 Facebook 开发的一种开源服务器端技术,用于优化 RESTful API 调用。它是一种执行引擎和一种数据查询语言。在本章中,咱们将探讨应用 GraphQL 的劣势。 为什么应用 GraphQL    RESTful API 遵循清晰且构造良好的面向资源的办法。然而,当数据变得更简单时,路由会变得更长。有时无奈通过单个申请获取数据。这就是 GraphQL 派上用场的中央。GraphQL 以图的模式构建数据,其弱小的查问语法用于遍历、检索和批改数据。    以下是应用 GraphQL 查询语言的劣势: 询问你想要的 - 并失去它    向您的 API 发送 GraphQL 查问并精确获取您须要的内容。GraphQL 查问总是返回可预测的后果。应用 GraphQL 的应用程序且稳固。与 Restful 服务不同,这些应用程序能够限度应该从服务器获取的数据。     以下示例将帮忙您更好地了解这一点:    让咱们思考一个具备属性 id、firstName、lastName 和 CollegeName 的业务对象 Student。假如一个挪动利用只须要获取 firstName 和 id。 如果咱们设计一个像 /api/v1/students 这样的 REST 端点,它最终会为一个 Student 对象的所有字段获取数据。这意味着,数据被 RESTful 服务适度获取。 这个问题能够通过应用 GraphQL 来解决。    思考上面给出的 GraphQL 查问: { { id firstName }}    这将仅返回 id 和 firstname 字段的值。该查问不会获取学生对象的其余属性的值。下面阐明的查问的响应如下所示: { "data": { "students": [ { "id": "S1001", "firstName": "Mohtashim" }, { "id": "S1002", "firstName": "Kannan" } ] }}在单个申请中获取多个资源    GraphQL 查问有助于顺利检索关联的业务对象,而典型的 REST API 须要从多个 URL 加载。GraphQL API 在单个申请中获取您的应用程序所需的所有数据。即便在迟缓的挪动网络连接上,应用 GraphQL 的应用程序也能够很快。    让咱们再思考一个业务对象 College,它具备以下属性:名称和地位。 Student 业务对象与 College 对象具备关联关系。如果咱们应用 REST API 来获取学生及其大学的详细信息,咱们最终将向服务器收回两个申请,如 /api/v1/students 和 /api/v1/colleges。这将导致每个申请的数据获取有余。 因而,挪动利用被迫屡次调用服务器以获取所需的数据。     然而,挪动利用能够应用 GraphQL 在单个申请中获取 Student 和 College 对象的详细信息。    以下是用于获取数据的 GraphQL 查问: ...

September 13, 2021 · 2 min · jiezi

关于graphql:一文了解近期Filecoin网络最新动态

**大题目一文理解近期Filecoin网络最新动静!**Linden灵动 明天 收录于话题 Filecoin网络2IPFS分布式存储3业余专一 共建共赢 9月1日,Filecoin全网无效算力冲破10EiB,迈入里程碑新阶段! 除了算力方面的惊人成就,Filecoin网络近期还产生了哪些小事?上面一起回顾一下吧 1 创立 DoraHacks Filecoin Grant黑客松闭幕 2021年DoraHacks Filecoin Grant黑客松投票环节拉下帷幕。该较量自5月1日继续进行至7月中旬,在获奖我的项目前三甲中共发放了约24.9万美元的处分。这些获奖我的项目将帮忙构建Filecoin网络将来。 公布Filecoin-Polygon Bridge Filecoin发表与Polygon单干,以减速两个生态之间的Web3互操作性。这项单干始于Textile团队近期创立的Filecoin-Polygon Bridge。 为进一步激励开发人员在桥上进行尝试和构建,Filecoin和Polygon为任何应用Textile Bridge的我的项目提供收费存储。单方还安顿了两场行将启动的联结黑客松,开发人员能够在此尝试搭建桥梁并构建新的应用程序。(点击此处理解单干详情) 02 存储 JigStack Gallery推动IPFS和Filecoin一体化 Gallery是JigstackDAO的最新解决方案,是一个由$STAK治理和激励的多个DeFi产品治理平台。Gallery是Jigstack进入NFT生态系统的入口,为NFT和STAK持有者发明新鲜和创意性的机会。 Gallery发表,他们将应用IPFS和Filecoin存储NFT,这也是他们行将官宣的打算中不可或缺的一部分。 为Mask Network提供去中心化存储 Mask Network和Filecoin发表单干,拟通过向Mask用户提供去中心化存储计划来桥接Web2和Web3。 Mask Network是连贯Web2平台和Web3准则的当先协定。Mask browser extension容许任何人在Facebook和Twitter等传统平台上与别人互动,但需应用Web3准则和解决方案。用户能够通过Gitcoin发送和接管加密音讯、转移加密货币或参加赞助我的项目,并且很快就能够通过Filecoin网络存储和共享文件。 通过Mask browser extension,用户可能抉择将特定文件上传至Filecoin网络,并将其作为加密或未加密的资产共享至他们的网络中。 Web3.Storage在The New Stack中的性能 The New Stack对Web3.Storage相当认同,且于近期推出了为开发人员提供收费拜访(实在且无限期)Filecoin网络的存储解决方案。 Web3.storage带来了冗余度和繁难应用形式,向更多的资深或老手Web3开发人员关上了通往去中心化存储世界的大门。 03 存储提供者 Filecoin社区批准扭转存储提供者术语 8月20日,通过数周征求整个Filecoin社区对Filecoin改良提案18 (FIP-0018)的意见和反馈后,Filecoin社区批准了FIP-0018,更改了存储市场及其存储提供者的命名约定。 此命名约定将在Filecoin文档网站、Githhub、Filecoin和Filecoin基金会官网社交媒体渠道以及其余生态工具中全面更新。 Lotus公布v 1.11.1版本 Lotus v1.11.1版本现已上线。此版本在交易和数据存储方面做出很多改良,并减少了新个性和bug修复。 Proofs公布v9.0.0&v9.0.1版本 Proofs v9.0.0&v9.0.1版本现已上线,并在lotus v1.11.2rc系列中标记,以供测试。这些版本将默认的bls381库从配对转换为blst,因为其通过审计和测量后在性能方面更胜一筹。 鉴于存储提供者在一段时间内根本都将blst作为可选性能,因而将其作为默认个性有其价值所在。这个版本还让外部线程库实现从rayon切换到yastl的转变,以改善并行工作负载中的调度。 04 ...

September 3, 2021 · 1 min · jiezi

关于graphql:深入GraphQL-的使用语法

深刻GraphQL 的应用语法对于GraphQL 的应用语法在上一节中曾经大略介绍了根本的应用形式了,这一篇将会对上一篇入门做拓展,致力将所有的应用语法都笼罩到。 1. 终端语法首先是介绍在前端查问时用的语法,分成Query 和Mutation 两局部,Subscription 的和Query 是相似的就不特地阐明了。 1.1 Query假如咱们当初有一个数据集,构造是这样的: 学生和老师各有各自的特有字段;学生中有个获取所有相干老师的办法,老师中也有一个获取所有学生的办法;学生和老师互为多对多关系;classDiagram Student <|-- Teacher2Student Teacher <|-- Teacher2Student class Student { +Int id +String name +Int age +teachers(id_eq: number) get_all_teachers } class Teacher { +Int id +String name +Boolean gender +students(name_contains: string) get_all_students } class Teacher2Student { +Int id +Int student_id +Int teacher_id +student() get_student +teacher() get_teacher }首先最简略的应用形式咱们可查: query { student { id name teacher { id name } }}# 后果:{ data: { student: [ { id: 1, name: "张三", teacher: [ { id: 1, name: "李老师" }, { id: 2, name: "吴老师" } ] }, { id: 2, name: "李四", teacher: [ { id: 1, name: "李老师" } ] }, { id: 3, name: "王三", teacher: [ { id: 2, name: "吴老师" } ] } ] }}咱们通过下面的查问能够失去总共有两个学生,其中李老师同时教了他们两人。这是最最根本的用法。上面咱们缓缓加查问需要去扭转后果。 ...

July 7, 2021 · 4 min · jiezi

关于graphql:GraphQL-概念入门

GraphQL 概念入门Restful is Great! But GraphQL is Better. -- My Humble Opinion. GraphQL will do to REST what JSON did to XML. -- Samer Buna from Quora GraphQL 作为 Facebook 的前端三架马车之一(另外两架是 Relay 和 React, 三者能够无缝联合),提出也有一段时间了,但真正用过的人却出奇的少,截止到 2018 年底,依据 Stateofjs 的数据看,尽管只有 1/5 的开发人员用过,但却有高达 62.5% 的人示意听过并想试试 果然咸鱼才是支流呀;接下来我会就 GraphQL 的前后端利用出个系列文章介绍 GraphQL 及其应用感触,顺便填坑。 本系列将以 Python + Django + Graphene 作为后端服务端。Apollo 作为前端客户端。 1. 什么是 GraphQL官网是这么说的: GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查问的运行时。 GraphQL 对你的 API 中的数据提供了一套易于了解的残缺形容,使得客户端可能精确地取得它须要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建弱小的开发者工具。我总结一下: ...

July 5, 2021 · 3 min · jiezi

关于graphql:GraphQL-入门指南

本文由智能化研发管理工具PingCode技术经理 龚林杰分享什么是 GraphQLA query language for your APIs GraphQL 是一种由 Facebook 提出的用于 API 的查询语言,也是一个满足你数据查问的运行时。 GraphQL 对你的 API 中的数据提供了一套易于了解的残缺形容,使得客户端可能精确地取得它须要的数据,而且没有任何冗余 罕用的API有哪些什么是APIAPI 全称:Application programming interface, API的实质就是读数据、写数据。 咱们罕用的API分成两个流派基于REST(Representational State Transfer)REST:体现层状态转移,是一种软件架构格调,而不是一个规范。REST 用 HTTP 封装,走的是 HTTP 协定。那么给予 REST 有哪些衍生品?RESTFUL: 操作资源 ,GraphQL: A query language for your APIs 基于RPC用自定义的协定 http, http2, 音讯队列(redis), tcp 等封装的一套近程调用的API,很典型的一个技术就是gRPC. 为什么要应用GraphQLREST API 存在的问题以及怎么应答POST / PUT / DELETE 傻傻分不清楚,有时候界线含糊因为是操作资源路由有时候会很长,如 /work-items/:id/comments/:cid/like数据返回冗余,叫 Overfetching数据返回短少一些字段,叫 Underfetching接口数据如何兼容不同平台咱们在应用REST接口时,接口返回的数据格式、数据类型都是后端事后定义好的,如果返回的数据格式并不是调用者所冀望的,作为前端的咱们能够通过以下两种形式来解决问题: 和后端沟通,改接口(更改数据源)本人做一些适配工作(解决数据源)后端专门为其余平台(挪动端)提供接口GraphQL 的劣势在哪借助 GraphQL,组织内的不同客户端应用程序能够轻松地仅查问所需数据,这一点超过了其它 REST 办法,并带来了理论应用程序性能的进步。应用传统的 REST API 端点,客户端应用程序将详询服务器资源,并承受蕴含了与申请匹配的所有数据的响应。如果来自 REST API 端点的胜利响应返回 35 个字段,那么客户端应用程序就会收到 35 个字段。 ...

June 22, 2021 · 3 min · jiezi

关于graphql:GraphQL及元数据驱动架构在后端BFF中的实践

GraphQL是Facebook提出的一种数据查询语言,外围个性是数据聚合和按需索取,目前被广泛应用于前后端之间,解决客户端灵便应用数据问题。本文介绍的是GraphQL的另一种实际,咱们将GraphQL下沉至后端BFF层之下,联合元数据技术,实现数据和加工逻辑的按需查问和执行。这样不仅解决了后端BFF层灵便应用数据的问题,这些字段加工逻辑还能够间接复用,大幅度晋升了研发的效率。本文介绍的实际计划曾经在美团局部业务场景中落地,并获得不错成果,心愿这些教训可能对大家有帮忙。1 BFF的由来BFF一词来自Sam Newman的一篇博文《Pattern:Backends For Frontends》,指的是服务于前端的后端。BFF是解决什么问题的呢?据原文形容,随着挪动互联网的衰亡,原适应于桌面Web的服务端性能心愿同时提供给挪动App应用,而在这个过程中存在这样的问题: 挪动App和桌面Web在UI局部存在差别。挪动App波及不同的端,不仅有iOS、还有Android,这些不同端的UI之间存在差别。原有后端性能和桌面Web UI之间曾经存在了较大的耦合。因为端的差异性存在,服务端的性能要针对端的差别进行适配和裁剪,而服务端的业务性能自身是绝对繁多的,这就产生了一个矛盾——服务端的繁多业务性能和端的差异性诉求之间的矛盾。那么这个问题怎么解决呢?这也是文章的副标题所形容的"Single-purpose Edge Services for UIs and external parties",引入BFF,由BFF来针对多端差别做适配,这也是目前业界宽泛应用的一种模式。 在理论业务的实际中,导致这种端差异性的起因有很多,有技术的起因,也有业务的起因。比方,用户的客户端是Android还是iOS,是大屏还是小屏,是什么版本。再比方,业务属于哪个行业,产品状态是什么,性能投放在什么场景,面向的用户群体是谁等等。这些因素都会带来面向端的性能逻辑的差异性。 在这个问题上,笔者所在团队负责的商品展现业务有肯定的发言权,同样的商品业务,在C端的展现性能逻辑,粗浅受到商品类型、所在行业、交易状态、投放场合、面向群体等因素的影响。同时,面向消费者端的性能频繁迭代的属性,更是加剧并深入了这种矛盾,使其演化成了一种服务端繁多稳固与端的差别灵便之间的矛盾,这也是商品展现(商品展现BFF)业务零碎存在的偶然性起因。本文次要在美团到店商品展现场景的背景下,介绍面临的一些问题及解决思路。 2 BFF背景下的外围矛盾BFF这层的引入是解决服务端繁多稳固与端的差别灵便诉求之间的矛盾,这个矛盾并不是不存在,而是转移了。由原来后端和前端之间的矛盾转移成了BFF和前端之间的矛盾。笔者所在团队的次要工作,就是和这种矛盾作奋斗。上面以具体的业务场景为例,联合以后的业务特点,阐明在BFF的生产模式下,咱们所面临的具体问题。下图是两个不同行业的团购货架展现模块,这两个模块咱们认为是两个商品的展现场景,它们是两套独立定义的产品逻辑,并且会各自迭代。 在业务倒退初期,这样的场景不多。BFF层零碎“烟囱式”建设,性能疾速开发上线满足业务的诉求,在这样的状况下,这种矛盾体现的不显著。而随着业务倒退,行业的开辟,造成了许许多多这样的商品展现性能,矛盾逐步加剧,次要体现在以下两个方面: 业务撑持效率:随着商品展现场景变得越来越多,API呈爆炸趋势,业务撑持效率和人力成线性关系,零碎能力难以撑持业务场景的规模化拓展。零碎复杂度高:外围性能继续迭代,外部逻辑充斥着if…else…,代码过程式编写,零碎复杂度较高,难以批改和保护。那么这些问题是怎么产生的呢?这要联合“烟囱式”零碎建设的背景和商品展现场景所面临的业务,以及零碎特点来进行了解。 特点一:内部依赖多、场景间取数存在差别、用户体验要求高 图例展现了两个不同行业的团购货架模块,这样一个看似不大的模块,后端在BFF层要调用20个以上的上游服务能力把数据拿全,这是其一。在下面两个不同的场景中,须要的数据源汇合存在差别,而且这种差别普遍存在,这是其二,比方足疗团购货架须要的某个数据源,在丽人团购货架上不须要,丽人团购货架须要的某个数据源,足疗团购货架不须要。只管依赖上游服务多,同时还要保障C端的用户体验,这是其三。 这几个特点给技术带来了不小的难题:1)聚合大小难管制,聚合性能是分场景建设?还是对立建设?如果分场景建设,必然存在不同场景反复编写相似聚合逻辑的问题。如果对立建设,那么一个大而全的数据聚合中必然会存在有效的调用。2)聚合逻辑的复杂性管制问题,在这么多的数据源的状况下,不仅要思考业务逻辑怎么写,还要思考异步调用的编排,在代码复杂度未能良好管制的状况下,后续聚合的变更批改将会是一个难题。 特点二:展现逻辑多、场景之间存在差别,共性共性逻辑耦合 咱们能够显著地辨认某一类场景的逻辑是存在共性的,比方团单相干的展现场景。直观能够看出基本上都是展现团单维度的信息,但这只是表象。实际上在模块的生成过程中存在诸多的差别,比方以下两种差别: 字段拼接逻辑差别:比方以上图中两个团购货架的团购题目为例,同样是题目,在丽人团购货架中的展现规定是:[类型] + 团购题目,而在足疗团购货架的展现规定是:团购题目。排序过滤逻辑差别:比方同样是团单列表,A场景依照销量倒排序,B场景依照价格排序,不同场景的排序逻辑不同。诸如此类的展现逻辑的差异性还有很多。相似的场景实际上在外部存在很多差别的逻辑,后端如何应答这种差异性是一个难题,上面是最常见的一种写法,通过读取具体的条件字段来做判断实现逻辑路由,如下所示: if(category == "丽人") { title = "[" + category + "]" + productTitle;} else if (category == "足疗") { title = productTitle;}这种计划在性能实现方面没有问题,也可能复用独特的逻辑。然而实际上在场景十分多的状况下,将会有十分多的差异性判断逻辑叠加在一起,性能始终会被继续迭代的状况下,能够设想,零碎将会变得越来越简单,越来越难以批改和保护。 总结:在BFF这层,不同商品展现场景存在差别。在业务倒退初期,零碎通过独立建设的形式反对业务疾速试错,在这种状况下,业务差异性带来的问题不显著。而随着业务的一直倒退,须要搭建及经营的场景越来越多,呈规模化趋势。此时,业务对技术效率提出了更高的要求。在这种场景多、场景间存在差别的背景下,如何满足场景拓展效率同时可能控制系统的复杂性,就是咱们业务场景中面临的外围问题。 3 BFF利用模式分析目前业界针对此类的解决方案次要有两种模式,一种是后端BFF模式,另一种是前端BFF模式。 3.1 后端BFF模式后端BFF模式指的是BFF由后端同学负责,这种模式目前最宽泛的实际是基于GraphQL搭建的后端BFF计划,具体是:后端将展现字段封装成展现服务,通过GraphQL编排之后裸露给前端应用。如下图所示: 这种模式最大的个性和劣势是,当展现字段曾经存在的状况下,后端不须要关怀前端差异性需要,按需查问的能力由GraphQL反对。这个个性能够很好地应答不同场景存在展现字段差异性这个问题,前端间接基于GraphQL按需查问数据即可,后端不须要变更。同时,借助GraphQL的编排和聚合查问能力,后端能够将逻辑合成在不同的展现服务中,因而在肯定水平上可能化解BFF这层的复杂性。 然而基于这种模式,依然存在几个问题:展现服务颗粒度问题、数据图划分问题以及字段扩散问题,下图是基于以后模式的具体案例: 1)展现服务颗粒度设计问题 这种计划要求展现逻辑和取数逻辑封装在一个模块中,造成一个展现服务(Presentation Service),如上图所示。而实际上展现逻辑和取数逻辑是多对多的关系,还是以前文提到的例子阐明: 背景:有两个展现服务,别离封装了商品题目和商品标签的查问能力。情景:此时PM提了一个需要,心愿商品在某个场景的题目以“[类型]+商品题目”的模式展现,此时商品题目的拼接依赖类型数据,而此时类型数据商品标签展现服务中曾经调用了。问题:商品题目展现服务本人调用类型数据还是将两个展现服务合并到一起?以上形容的问题的是展现服务颗粒度把控的问题,咱们能够狐疑上述的示例是不是因为展现服务的颗粒度过小?那么反过来看一看,如果将两个服务合并到一起,那么势必又会存在冗余。这是展现服务设计的难点,外围起因在于,展现逻辑和取数逻辑自身是多对多的关系,后果却被设计放在了一起。 2)数据图划分问题 通过GraphQL将多个展现服务的数据聚合到一张图(GraphQL Schema)中,造成一个数据视图,须要数据的时候只有数据在图中,就能够基于Query按需查问。那么问题来了,这个图应该怎么组织?是一张图还是多张图?图过大的话,势必带来简单的数据关系保护问题,图过小则将会升高计划自身的价值。 3)展现服务外部复杂性 + 模型扩散问题 ...

May 7, 2021 · 2 min · jiezi

关于graphql:GraphQL总结

依据后面的学习,能够发现 GraphQL 带来了很多便当和翻新。具备以下几个次要的劣势: 1、缩小数据冗余和申请冗余,能够更获取和应用数据;2、灵便而强类型的 schema,GraphQL 是强类型的,他能够帮忙开发者防止很多问题;3、因为强类型的应用,GraphQL 能够自动化地对收到的数据进行测验;4、GraphQL 不须要进行接口文档保护,它能主动生成,加之其自省性能,能够说很不便;5、进步开发效率,缩小代码变更次数,长期保护老本升高;只管 GraphQL 有很多劣势,但万物并不是完满的,其也有如下的毛病,正是这些导致其没有被大规模应用: 1、成熟的解决方案比拟少,引入 GraphQL 老本略高,危险也不小,这就很大水平上限度了受众;2、减轻前后端利用比重,前端会带一个 graphql-client,缩短用户等待时间;3、GraphQL 产生大量冗余查问,尽管网络层面的申请数被优化了,但GraphQL的每一个实体背地可能对应着不同的数据库甚至不同类型的存储集群,后端集群间的海量数据查问便会成为性能瓶颈。绝对于resetful,有显著的降性能的状况;4、GraphQL 的利好次要是在于前端的开发效率,但落地却须要服务端的全力配合,对于曾经成熟的公司技术栈,要推动 GraphQL 还是会遇到各种合作上的阻力;5、谬误提醒不敌对,REST API的状况下,咱们不须要解析Response的内容,只须要看HTTP status code和message,就能晓得申请是否胜利,大略问题是什么,处理错误的程序也非常容易编写。然而GraphQL只有Service自身还在失常运行,咱们就会失去200的HTTP status,须要专门查看response的内容才晓得是否有error,这时须要全局中间件解决 http error code 到graph-error的映射;总结GraphQL 最大的劣势,就是它可能大大提高开发者的效率,而且最大化地简化了前端的数据层的复杂性,使得前后端对数据的组织观点统一。但咱们抉择一项技术时,须要考查其 scale、performance、tech stack、migration等多方面的因素,否则它可能不仅没能提高效率和性能,反倒制作出更多的问题。

January 29, 2021 · 1 min · jiezi

关于graphql:GraphQL-接口设计

文章原文请移步我的博客:GraphQL 接口设计 graphql 是一种用于 API 的查询语言。它提供了一套残缺的和易于了解的 API 接口数据形容,给客户端势力去精准查问他们须要的数据,而不必再去实现其余更多的代码,使 API 接口开发变得更简略高效。 最近在用Gatsby开发一版动态博客,感觉和这个框架真是相见恨晚。因为这个框架应用到了graphql技术,所以我花了点工夫去学习了一下,并且记录了一下学习和思考过程。 本文次要解说如何了解graphql以及基于关系型数据库设计graphql的思路。如果须要学习graphql基础知识,请移步官网文档 本文蕴含Nestjs + graphql的示例我的项目:https://github.com/YES-Lee/nestjs-graphql-starter 了解graphqlgraphql是一个用于形容数据及其关系的查询语言,官网文档中形容了graphql的规范,具体的实现依附第三方,目前支流的是Apollo提供的解决方案。 graphql并不关怀具体咱们是怎么获取数据的,咱们只须要提供获取数据的办法(resolver)以及如何组装数据(schema)。相似于Java开发过程中的接口设计模式,Graphql定义了一套规范,咱们依照规范实现接口。上面以用户-角色模型举例。 上面的代码定义了两个数据结构,与JSON相似,应该很容易了解。它形容了每个类型(type)的名称,以及其蕴含的属性。属性除了能够是根本类型外,也能够是数组、其余援用类型,从而建设起所有数据模型及互相的关系图。 type Role { name: String note: String}type User { id: Int name: String gender: Int role: Role}下面代码用于形容Role和User的数据结构,那么咱们具体要怎么应用这个货色呢?先从前端的角度来看,能够从官网文档学习到前端的根本应用,申请体中的数据形容和下面定义类型的代码有些许差异,比方咱们要查问用户数据: query userInfo { user(id: Int) { id name gender role { name note } }}从下面的代码能够大略猜测出,如果咱们不须要查问role数据是,只须要将其从申请中去掉 query userInfo { user(id: Int) { id name gender }}当申请达到服务端时,graphql会对申请体进行解析,当解析到user时,会执行咱们定义好的获取user数据的逻辑,解析到role也是同样的情理。那么咱们得在服务端定义好获取数据的逻辑,在graphql中叫做resolver。 之前的代码只定义了数据的构造,咱们还须要为其创立一个resolver来获取对应的数据,相似于上面的代码 function userResolver (id) { // ... // return User}function roleResolver (userId) { // ... // return Role}咱们能够在resolver中执行sql、http申请、rpc通信等任何可能获取到所需数据的逻辑。最终只须要依照预约义的构造将数据返回即可。 ...

December 15, 2020 · 2 min · jiezi

关于graphql:三分钟快速解析GraphQL基本工作思路

欢送浏览 ???? 本文会通过理论场景介绍一下 GraphQL,目标是让你疾速理解 GraphQL 是什么,以及根本工作思路,不蕴含理论用法,所以浏览很轻松。 一、GraphQL 是什么?GraphQL 是后端数据查询语言,能够简略了解为 GraphQL 对标的是 REST 接口。 GraphQL 由 Facebook 开源,目前曾经在 Facebook 中撑持千亿级的 API 接口调用,在 Facebook 之外正在被迅速利用。 咱们不要被 GraphQL 这个名字误导了,第一次看见它时,我还认为这是一个图数据库的查询语言呢。 GraphQL 大体上确实是 "图查问" 的意思,但这个 "图" 是数据图谱的意思,不是图数据库。 二、GraphQL 思路 以上图为例,这是支流的 Feed 流模式,如何实现呢? 定下来界面中须要显示哪些数据元素之后,后端开始为其定制一个 REST 接口,查问出相干数据: Post 帖子作者Like 喜爱Comment 评论Share 分享后端程序员进行数据关联查问,取出其中须要的数据项,而后封装为一个易于前端操作的数据结构,例如 JSON 对象。 这样 Feed 流的接口就 OK 了,同样的,对于其余界面再进行相应的接口开发。 例如在帖子详情页面,波及的数据还是 Feed 流中的这些,但具体的数据项不同了,例如: 帖子须要全文Like 须要点赞用户的图像列表、IDComment 评论须要详情列表因为数据项的不同,就须要针对这个界面需要从新开发吧。 如果你嫌麻烦,提供了一个大而全的接口,后端开发是简略了,但新问题来了,例如: 前端开发须要从后果数据中认真挑出本人所须要的数据项。接口返回数据中蕴含大量的前端无用数据,会占用更多的带宽,影响性能,例如 Facebook 那种千亿级的 API 调用量,这种带宽的节约是不能容忍的。有什么更好的方法呢?(如果你有更好的教训,欢送发给我,我会分享给大家) Facebook 为了解决这个问题,设计出了 GraphQL。 ...

November 11, 2020 · 1 min · jiezi

关于graphql:GraphQL初体验Nodejs构建GraphQL-API指南

原文:https://blog.heroku.com作者:CHRIS CASTLE微信搜寻【前端全栈开发者】关注这个脱发、摆摊、卖货、继续学习的程序员,第一工夫浏览最新文章,会优先两天发表新文章。关注即可大礼包,准能为你节俭不少钱! 在过来的几年中,GraphQL曾经成为一种十分风行的API标准,该标准专一于使客户端(无论客户端是前端还是第三方)的数据获取更加容易。 在传统的基于REST的API办法中,客户端发出请求,而服务器决定响应: curl https://api.heroku.space/users/1{ "id": 1, "name": "Luke", "email": "luke@heroku.space", "addresses": [ { "street": "1234 Rodeo Drive", "city": "Los Angeles", "country": "USA" } ]}然而,在GraphQL中,客户端能够准确地确定其从服务器获取的数据。例如,客户端可能只须要用户名和电子邮件,而不须要任何地址信息: curl -X POST https://api.heroku.space/graphql -d 'query { user(id: 1) { name email }}{ "data": { "name": "Luke", "email": "luke@heroku.space" }}通过这种新的模式,客户能够通过缩减响应来满足他们的需要,从而向服务器进行更高效的查问。对于单页利用(SPA)或其余前端重度客户端利用,能够通过缩小有效载荷大小来放慢渲染工夫。然而,与任何框架或语言一样,GraphQL也须要衡量取舍。在本文中,咱们将探讨应用GraphQL作为API的查询语言的利弊,以及如何开始构建实现。 为什么抉择GraphQL?与任何技术决策一样,理解GraphQL为你的我的项目提供了哪些劣势是很重要的,而不是简略地因为它是一个风行词而抉择它。 思考一个应用API连贯到近程数据库的SaaS应用程序。你想要出现用户的个人资料页面,你可能须要进行一次API GET 调用,以获取无关用户的信息,例如用户名或电子邮件。而后,你可能须要进行另一个API调用以获取无关地址的信息,该信息存储在另一个表中。随着应用程序的倒退,因为其构建形式的起因,你可能须要持续对不同地位进行更多的API调用。尽管每一个API调用都能够异步实现,但你也必须解决它们的响应,无论是谬误、网络超时,甚至暂停页面渲染,直到收到所有数据。如上所述,这些响应的有效载荷可能超过了渲染你以后页面的须要,而且每个API调用都有网络提早,总的提早加起来可能很可观。 应用GraphQL,你无需进行多个API调用(例如 GET /user/:id 和 GET /user/:id/addresses ),而是进行一次API调用并将查问提交到单个端点: query { user(id: 1) { name email addresses { street city country } }}而后,GraphQL仅提供一个端点来查问所需的所有域逻辑。如果你的应用程序一直增长,你会发现自己在你的架构中增加了更多的数据存储——PostgreSQL可能是存储用户信息的好中央,而Redis可能是存储其余品种信息的好中央——对GraphQL端点的一次调用将解决所有这些不同的地位,并以他们所申请的数据响应客户端。 ...

October 5, 2020 · 3 min · jiezi

关于graphql:GraphQL初体验Nodejs构建GraphQL-API指南

作者:CHRIS CASTLE原文:https://blog.heroku.com译者:杜尼卜微信搜寻【前端全栈开发者】关注这个脱发、摆摊、卖货、继续学习的程序员的公众号,第一工夫浏览最新文章,会优先两天发表新文章。关注即可大礼包,送某网精品视频课程网盘材料,准能为你节俭不少钱! 在过来的几年中,GraphQL曾经成为一种十分风行的API标准,该标准专一于使客户端(无论客户端是前端还是第三方)的数据获取更加容易。 在传统的基于REST的API办法中,客户端发出请求,而服务器决定响应: curl https://api.heroku.space/users/1{ "id": 1, "name": "Luke", "email": "luke@heroku.space", "addresses": [ { "street": "1234 Rodeo Drive", "city": "Los Angeles", "country": "USA" } ]}然而,在GraphQL中,客户端能够准确地确定其从服务器获取的数据。例如,客户端可能只须要用户名和电子邮件,而不须要任何地址信息: curl -X POST https://api.heroku.space/graphql -d 'query { user(id: 1) { name email }}{ "data": { "name": "Luke", "email": "luke@heroku.space" }}通过这种新的模式,客户能够通过缩减响应来满足他们的需要,从而向服务器进行更高效的查问。对于单页利用(SPA)或其余前端重度客户端利用,能够通过缩小有效载荷大小来放慢渲染工夫。然而,与任何框架或语言一样,GraphQL也须要衡量取舍。在本文中,咱们将探讨应用GraphQL作为API的查询语言的利弊,以及如何开始构建实现。 为什么抉择GraphQL? 与任何技术决策一样,理解GraphQL为你的我的项目提供了哪些劣势是很重要的,而不是简略地因为它是一个风行词而抉择它。 思考一个应用API连贯到近程数据库的SaaS应用程序。你想要出现用户的个人资料页面,你可能须要进行一次API GET 调用,以获取无关用户的信息,例如用户名或电子邮件。而后,你可能须要进行另一个API调用以获取无关地址的信息,该信息存储在另一个表中。随着应用程序的倒退,因为其构建形式的起因,你可能须要持续对不同地位进行更多的API调用。尽管每一个API调用都能够异步实现,但你也必须解决它们的响应,无论是谬误、网络超时,甚至暂停页面渲染,直到收到所有数据。如上所述,这些响应的有效载荷可能超过了渲染你以后页面的须要,而且每个API调用都有网络提早,总的提早加起来可能很可观。 应用GraphQL,你无需进行多个API调用(例如 GET /user/:id 和 GET /user/:id/addresses ),而是进行一次API调用并将查问提交到单个端点: query { user(id: 1) { name email addresses { street city country } }}而后,GraphQL仅提供一个端点来查问所需的所有域逻辑。如果你的应用程序一直增长,你会发现自己在你的架构中增加了更多的数据存储——PostgreSQL可能是存储用户信息的好中央,而Redis可能是存储其余品种信息的好中央——对GraphQL端点的一次调用将解决所有这些不同的地位,并以他们所申请的数据响应客户端。 ...

September 29, 2020 · 3 min · jiezi

Java中的GraphQL服务器第二部分了解解析器

第二部分:了解解析器 在第一部分中,我们开发了一个非常简单的GraphQL服务器。该解决方案有一个严重的缺陷:所有字段都急切地加载到后端,即使前端未要求也是如此。通过不给客户任何选择,我们通过RESTful服务来接受这种情况。RESTful API始终返回所有内容,这意味着始终加载所有内容。另一方面,如果将RESTful API分为多个较小的资源,则可能会面临N + 1问题和多次网络往返的风险。GraphQL是专门为解决以下问题而设计的: 仅获取必需的数据,以避免额外的网络流量以及后端不必要的工作允许在单个请求中获取客户端所需的尽可能多的数据,以减少总体延迟RESTful API可以任意决定要返回多少数据,因此几乎无法解决上述问题。它要么获取过多,要么获取不足。好的,这是理论,但是我们对GraphQL服务器的实现不能以这种方式工作。无论是否请求,它仍将获取所有数据。伤心。 不断发展您的API要回顾一下我们的API返回一个实例PlayerDTO: @Valueclass Player { UUID id; String name; int points; ImmutableList<Item> inventory; Billing billing;}与此GraphQL模式匹配的: type Player { id: String! name: String! points: Int! inventory: [Item!]! billing: Billing!}通过仔细地分析我们的应用程序,我意识到很少有客户billing在他们的查询中提出要求,但是我们必须始终提出要求billingRepository才能创建Player实例。许多急切的,不需要的工作: private final BillingRepository billingRepository;private final InventoryClient inventoryClient;private final PlayerMetadata playerMetadata;private final PointsCalculator pointsCalculator;//...@NotNullprivate Player somePlayer() { UUID playerId = UUID.randomUUID(); return new Player( playerId, playerMetadata.lookupName(playerId), pointsCalculator.pointsOf(playerId), inventoryClient.loadInventory(playerId), billingRepository.forUser(playerId) );}像这样的字段billing只能在请求时加载!为了了解如何使我们的对象的某些部分_图_(Graph-QL是也)懒加载,让我们添加一个名为新特性trustworthiness到Player上: type Player { id: String! name: String! points: Int! inventory: [Item!]! billing: Billing! trustworthiness: Float!}此更改是向后兼容的。事实上,GraphQL实际上没有API版本控制的概念。那么迁移路径是什么?有以下几种情况: ...

July 6, 2020 · 1 min · jiezi

GraphQL-如何一次获取多个资源

广告Vue.js小书已经出版,尤小右作序推荐:http://www.ituring.com.cn/boo...欢迎购买。Swift iOS 小书 http://www.ituring.com.cn/boo... 正文GraphQL 原来2012年就已经开源,算来也有不少历史了,但是看起来网络资料并不太多,大家普遍还是觉得麻烦。单单看官方手册好像就太不亲人的,太容易从自己的角度去描述细节,而不是从使用的角度去剖析,这也是官方手册普遍的问题。 比如“获取多个资源,只用一个请求”,官方说: GraphQL 查询不仅能够获得资源的属性,还能沿着资源间引用进一步查询。典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。这样一来,即使是比较慢的移动网络连接下,使用 GraphQL 的应用也能表现得足够迅速。因为他假设你知道REST API,并且和它对比。其实,认识一个新事物,认识它本身会更直接,认识清楚了,想要对比了再去对比才有价值。但是人们太喜欢使用类别了。 我曾经写过一个高点击率的文章,讲述了vuex是什么,因为大家普遍反映官方文档不好懂,原因是是它上来和reactive那套东西对比。作者这样做可以理解,因为他就是对比着做的,说出来的也是对比的话,也认为这是干货。但是读者就不太好了解,因为我vue还没有搞利索,现在你让我搞搞reactive才能动vue的东西。这很令人绝望。 我们还是从一个案例开始。假设我有两个数据实体,一个是book,一个是author,且book和author是1:对多的关系。它的数据样本,看起来是这样的: var books = [ {id:0,title:"null book",author:{name:"reco"}}, {id:1,title:"the little prince",author:{name:"reco"}}, {id:2,title:"the http book",author:{name:"reco"}}]var authors = [ {id:1,name:"reco",books:[{title:"the little prince"},{title:"the http book"}]}, {id:2,name:"rita",books:[{title:"the swift book"}]}]就是这样的数据源。如果使用Graphql来做查询,可以查询作者列表,且对作者对书籍的引用做进一步查询,也就是希望这样的查询: {authors{name,books{title}}}可以返回: { "data": { "authors": [ { "name": "reco", "books": [ { "title": "the little prince" }, { "title": "the http book" } ] }, { "name": "rita", "books": [ { "title": "the swift book" } ] } ] }}对author.name的查询,就是获取对象属性,是比较容易的,而对而对关联对象的延伸查询,其实和属性一模一样,只不过看起来是嵌套的而已。明确了目标,我们把代码跑起来,也还是typeDefs+resolvers的一套东西: ...

June 5, 2020 · 1 min · jiezi

前端请求graphql的数据格式之我见

前端请求后端数据,vue-cli用graphql的方法去请求:刚开始我们用ajax,axios去请求后端数据,无往不利。可是,在某一天,突然,要用graphql来请求数据! 心里一慌,没事,来者不拒。 第一步:我们定义一个新的js,xxx.js:import gql from "graphql-tag";export const getApoVal = { xxxName: gql` query { xxxBackName{ name age } } `,}上面就是类似get请求了。xxxName:随便起一个名字;xxxBackName:这是后端的字符串名字;name,age:后端传过来的属性名字。后端的字符串一定要一一对应,不对应就会报红色的error,哈哈哈! 有参数怎么办?export const getApoVal = { xxxName: gql` query APIQuery($page: Int, $pageSize: Int){ xxxBackName(page: $page, pageSize: $pageSize){ name age } } `,}完美解决你的get方法参数问题。 第二步,教你post方法获取:export const submitApoVal= { xxxName: gql` mutation APIMutation($page: Int, $pageSize: Int){ xxxBackName(page: $page, pageSize: $pageSize){ name age } } `,}是不是很简单?query改成mutation,这就是要点,还是要和后端字符串一一对应! 到这里,你已经可以完美获取后端数据。感谢大家的支持!!

June 26, 2019 · 1 min · jiezi

用TypeScript-GraphQL查询SpaceX-火箭发射数据????

翻译:疯狂的技术宅https://blog.logrocket.com/bu... 未经允许,严禁转载 近一两年来 GraphQL 和 TypeScript 的使用都程爆发式增长,当两者与React结合使用时,它们可以为开发人员提供理想的开发体验。 GraphQL 改变了我们对 API 的思考方式,并利用直观的键/值对匹配,客户端可以请求在网页或移动应用屏幕上显示所需的确切数据。 TypeScript 通过为变量添加静态类型来扩展 JavaScript,从而减少了错误并提高了代码的可读性。 本文将引导你使用 React 和 Apollo 构建客户端应用程序,并调用 SpaceX 的公共 GraphQL API ,来显示有关的发射信息。我们将自动为查询生成 TypeScript 类型,并使用 React Hooks 执行这些查询。 本文假设你对 React,GraphQL 和 TypeScript 有一定的了解,并且正在研究怎样通过把它们集成在一起来构建一个正常运行的程序。如果你需要补充一些基础知识的话,可以关注公众号“前端先锋”。 如果你在学习的过程中遇到困难,可以参考源代码或查看 live app。 为什么选择 GraphQL + TypeScript?GraphQL API 需要强类型化,数据从单个端点提供。通过在此端点上调用 GET 请求,客户端可以接收后端的完全自我描述的数据,包括所有可用的数据和相应的类型。 通过 GraphQL 代码生成器,我们可以扫描 Web 应用目录中的查询文件,并将它们与 GraphQL API 提供的信息进行匹配,这样以来就可以创建 TypeScript 类型所有请求数据。通过使用 GraphQL,我们可以自动且自由地输入我们的 React 组件的属性。这样可以减少产品上的错误并提高迭代速度。 入门我们将使用带有 TypeScript 配置的 create-react-app 来创建程序。首先执行以下命令: npx create-react-app graphql-typescript-react --typescript// NOTE - you will need Node v8.10.0+ and NPM v5.2+通过使用 --typescript 标志,CRA 将为你生成项目文件和 .ts 和 .tsx,它将创建一个 tsconfig.json 文件。 ...

June 13, 2019 · 6 min · jiezi

这才是GraphQL最详尽的解释

翻译:疯狂的技术宅原文:https://opensource.com/articl... 未经允许严禁转载 GraphQL是一种查询语言、一种执行引擎和一种规范,它引领开发人员重新思考应该怎样去构建客户端和API。 GraphQL 是当今软件技术领域最大的流行语之一。但它究竟是什么?它是一种像 SQL 这样的查询语言吗?像 JVM 这样的执行引擎?像 XML 这样的规范? 只有回答了以上所有问题,才是正确答案! GraphQL 是一种查询语言语法,与编程语言无关的执行引擎,以及不断发展的规范。 让我们深入了解 GraphQL 是怎样成为这些东西的,并探究人们对此感到兴奋的原因。 查询语言GraphQL 作为一种查询语言似乎是合理的 —— 毕竟其中包含了“QL”这个字眼。但是我们在查询什么呢?下面关于查询请求和对应的响应的例子可能会对你的理解有所帮助。 以下用户查询: { user(id: 4) { name email phoneNumber }}可能会返回以下 JSON 响应: { "user": { "name": "Zach Lendon" “email”: “zach@hydrate.io” “phoneNumber”: “867-5309” }}假设客户端程序查询 user 的详细信息,然后获取结果并显示在屏幕上。作为一种查询语言,GraphQL 的核心优势之一是客户端程序只能请求其所需要的数据,并以一致的形式返回它。 但什么是返回 GraphQL 响应?这就是执行引擎(通常以GraphQL服务器的形式)的用武之地。 执行引擎 GraphQL 执行引擎负责处理 GraphQL 查询并返回 JSON 响应。所有 GraphQL 服务器都由两个核心组件组成:模式和解析器,这两个组件分别定义了执行引擎的结构和行为。 GraphQL schema 是一种自定义类型语言,它公开了 GraphQL 服务器实现允许(有效的)和处理哪些查询。上面的用户查询案例的架构可以如下所示: type User { name: String email: String phoneNumber: String}type Query { user: User}这些 schema 定义了返回 user 数据的查询。客户端可以通过 user 查询请求 user 的所有字段,GraphQL 服务器在响应中仅返回那些字段。通过使用强类型模式,GraphQL 服务器可以验证传入的查询,以确保它们基于所定义的 schema。 ...

June 12, 2019 · 1 min · jiezi

GraphQL一个简单的入门示例

GraphQL一个简单的入门示例准备npm i --save express express-graphql graphql cors服务端代码var express = require('express');var graphqlHTTP = require('express-graphql');const { buildSchema } = require('graphql');const cors = require('cors'); // 用来解决跨域问题// 创建 schema,需要注意到:// 1. 感叹号 ! 代表 not-null// 2. rollDice 接受参数const schema = buildSchema(` type Query { username: String age: Int! }`)const root = { username: () => { return '李华' }, age: () => { return Math.ceil(Math.random() * 100) },}const app = express();app.use(cors());app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: root, graphiql: true}))app.listen(3300);console.log('Running a GraphQL API server at http://localhost:3300/graphql')客户端代码<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>graphql demo</title></head><body> <button class="test">获取当前用户数据</button> <p class="username"></p> <p class="age"></p></body><script> var test = document.querySelector('.test'); test.onclick = function () { var username = document.querySelector('.username'); var age = document.querySelector('.age'); fetch('http://localhost:3300/graphql', { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, method: 'POST', body: JSON.stringify({ query: `{ username, age, }` }), mode: 'cors' // no-cors, cors, *same-origin }) .then(function (response) { return response.json(); }) .then(function (res) { console.log('返回结果', res); username.innerHTML = `姓名:${res.data.username}`; age.innerHTML = `年龄:${res.data.age}` }) .catch(err => { console.error('错误', err); }); }</script></html>运行结果 ...

June 11, 2019 · 1 min · jiezi

GraphQL从入门到实战

前言本来这篇文章准备51假期期间就发出来的,但是因为自己的笔记本电脑出了一点问题,所以拖到了现在????。为了大家更好的学习GraphQL,我写一个前后端的GraphQL的Demo,包含了登陆,增加数据,获取数据一些常见的操作。前端使用了Vue和TypeScript,后端使用的是Koa和GraphQL。 这个是预览的地址: GraphQLDeom 默认用户root,密码root 这个是源码的地址: learn-graphql GraphQL入门以及相关概念什么是GraphQL?按照官方文档中给出的定义, "GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具"。但是我在使用之后发现,gql需要后端做的太多了,类型系统对于前端很美好,但是对于后端来说可能意味着多次的数据库查询。虽然gql实现了http请求上的优化,但是后端io的性能也应当是我们所考虑的。 查询和变更GraphQL中操作类型主要分为查询和变更(还有subscription订阅),分别对应query,mutation关键字。query,mutation的操作名称operation name是可以省略的。但是添加操作名称可以避免歧义。操作可以传递不同的参数,例如getHomeInfo中分页参数,AddNote中笔记的属性参数。下文中,我们主要对query和mutation进行展开。 query getHomeInfo { users(pagestart: ${pagestart}, pagesize: ${pagesize}) { data { id name createDate } }}mutation AddNote { addNote(note: { title: "${title}", detail: "${detail}", uId: "${uId}" }) { code }}Schema全称Schema Definition Language。GraphQL实现了一种可读的模式语法,SDL和JavaScript类似,这种语法必须存储为String格式。我们需要区分GraphQL Schema和Mongoose Schema的区别。GraphQL Schema声明了返回的数据和结构。Mongoose Schema则声明了数据存储结构。 类型系统标量类型GraphQL提供了一些默认的标量类型, Int, Float, String, Boolean, ID。GraphQL支持自定义标量类型,我们会在后面介绍到。 对象类型对象类型是Schema中最常见的类型,允许嵌套和循环引用 type TypeName { fieldA: String fieldB: Boolean fieldC: Int fieldD: CustomType}查询类型查询类型用于获取数据,类似REST GET。Query是Schema的起点,是根级类型之一,Query描述了我们可以获取的数据。下面的例子中定义了两种查询,getBooks,getAuthors。 ...

June 9, 2019 · 5 min · jiezi

手搭一个-ReactTypescriptKoaGraphQL-环境

本文系原创,转载请附带作者信息:yhlben项目地址:https://github.com/yhlben/cdfang-spider 前言在实际的开发过程中,从零开始初始化一个项目往往很麻烦,所以各种各样的脚手架工具应运而生。crea-react-app,vue-cli,@angular/cli 等脚手架工具,只需要执行一个命令,项目结构以及开发环境就搭建好了。 脚手架工具确实方便了我们使用,开发者可以专注于业务,而不需要考虑太多的环境搭建。但作者认为,学习脚手架工具背后的搭建过程也是很重要的,以防脚手架挂了之后,我们还能正常搭建项目。基于这个目的,作者从零搭建了cdfang-spider项目。 现在让我们就以这个项目为例,从零开始搭建项目吧。 项目选型三大框架里选哪个? react 个人爱好。react-router 定义路由。react context 状态管理。react hooks 组件化。引入强类型语言? typescript。为 js 提供类型支持,编辑器友好,增加代码可维护性,使用起来心里踏实。在使用第三方库时,可以写出更加符合规范的代码,避免 api 乱用等。项目中依赖了大量 @types/xxx 包,无形中增加了项目体积。编辑器对 ts 文件进行类型检查,需要遍历 node_modules 目录下所有的 @types 文件,会造成编辑器卡顿现象。目前仍然存在很多库没有 @types 支持,使用起来并不方便。css 选型? 预编译器 less。项目中使用了变量定义,选择器嵌套,选择器复用等,less 够用了。解决命名冲突可以使用 css modules,暂未考虑 css in js。使用 bem 命名规范。使用 postcss 插件 autoprefixer,增加 css 兼容性。构建工具选哪个? webpack。内置 tree shaking,scope hosting 等,打包效率高,社区活跃。webpack-merge 合并不同环境配置文件。配置 externals。引入 cdn 代替 node_modules 中体积较大的包。gulp。用来打包 node 端代码。代码规范检查? eslint。辅助编码规范执行,有效控制代码质量。同时也支持校验 typescript 语法。配置 eslint-config-airbnb 规则。配置 eslint-config-prettier 关闭和 prettier 冲突的规则。测试框架选型? ...

May 29, 2019 · 4 min · jiezi

CuteJavaScriptGraphQL真香入门教程

看完复联四,我整理了这份 GraphQL 入门教程,哈哈真香。。。 欢迎关注我的 个人主页 && 个人博客 && 个人知识库 && 微信公众号“前端自习课”首先有请阿爸镇贴!哈哈哈,需要高清原图的小伙伴可以 点我下载 阿爸无敌 。 下面开始本文内容: 一、GraphQL介绍GraphQL 是 Facebook 开发的一种 API 的查询语言,与 2015 年公开发布,是 REST API 的替代品。 GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。 官网: http://graphql.org/ 中文网: http://graphql.cn/ 1. 特点请求你所要的数据,不多不少;如:hero 中有 name, age, sex 等,可以只取得需要的字段。 获取多个资源,只用一个请求;典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。这样也能保证在较慢的移动网络连接下,使用 GraphQL 的应用也能表现得足够迅速。 描述所有可能类型的系统。便于维护,根据需求平滑演进,添加或隐藏字段;GraphQL 使用类型来保证应用只请求可能的数据,还提供了清晰的辅助性错误信息。应用可以使用类型,而避免编写手动解析代码。 2. 简单案例这里先看下简单案例,体验下 GraphQL 的神奇之处(后面详细介绍)。 我们这样定义查询语句: query { hero}然后得到的就是我们所要查询的 hero 字段: ...

May 10, 2019 · 8 min · jiezi

Apollo-Server-集成性能监控

Apollo Server开箱支持Apollo Engine,只是由于某些不可知的原因Apollo Engine的 API 在国内不可访问(我是真不知道为什么这个 API 会被墙的),所以只能另外想办法了. Apollo Server本身有一个Apollo Tracing可以用于性能监控的扩展,通过扩展Apollo Tracing收集指标传输到分布式跟踪系统中.另外有一个开源库Apollo Opentracing可以收集指标,传输到Jaeger或者Zipkin中,通过Jaeger或Zipkin实现性能监控和分析. 秉着方便,直接使用Apollo Opentracing.分布式跟踪系统使用Jaeger. 使用 Docker 搭建JaegerJaeger 官方文档 在浏览器打开 http://localhost:16686 访问Jaeger 搭建Apollo Servermkdir apollo-opentracing-democd apollo-opentracing-demoyarn init -yyarn add apollo-server// index.jsconst { ApolloServer, gql } = require('apollo-server')const typeDefs = gql` type Query { hello: String }`const resolvers = { Query: { hello: () => 'world', },}const server = new ApolloServer({ typeDefs, resolvers,})server.listen().then(({ url }) => { console.log(`???? Server ready at ${url}`)})运行 ...

April 29, 2019 · 1 min · jiezi

RPC-RESTGraphQL三种API设计方式的简介和比较

RPCRPC=remote procedure call,执行远程服务器上的一个function,举例:服务端定义了三个函数: 客户端发起请求 RPC在一些大公司中依然被使用。RPC的优点有: 设计简洁,便于理解轻量的payload很高的性能表现缺点有: 前后端代码高耦合代码可读性不好,相关代码不容易被定位会导致有大量被定义的函数,难以管理RESTREST = Representational state transfer,直接翻译就是『表现层状态转移』优点: 前后端高度解耦便于理解,即使没有看文档,也能大概知道接口是用来做什么的;接口的功能有单一性,便于扩展和复用;利用了HTTP原本的特性缺点: 有时payload会变的特别大同一个页面可能要调用很多个API,来获取不同的东西,在网络差的情况下会降低体验举例: GraphQLGraphQL = Graph query language吸取了RPC和REST的一些共同优点;以查询为基本单元,方便获取到想要的数据,举例:接口定义接口调用优点: 低网络速度下表现优异声明式地数据获取根据UI需求获取合适的数据,避免不必要的数据传输缺点: 定义起来相对复杂缓存问题,需要一个更加健全的机制中来确保字段级别的缓存版本持续更新中,还不太成熟综合对比与总结API设计也不会有银弹。设计API时,决定使用哪种形式,得先考虑所设计的API将会被谁使用: 如果是关注于对象和资源的项目,需要对接各种不同的端和使用者,需要便于使用和阅读文档,那么适合使用REST如果是面向行为动作,或者内部的一些微服务,对响应要求高,那么可以考虑RPC如果是需要给UI提供数据,或者需要对弱网络环境下优化而减少请求,那么可以考虑GraphQL 参考来源https://www.youtube.com/watch...

April 26, 2019 · 1 min · jiezi

Graphql实战系列(下)

前情介绍在《Graphql实战系列(上)》中我们已经完成技术选型,并将graphql桥接到凝胶gels项目中,并动态手写了schema,可以通过 http://localhost:5000/graphql 查看效果。这一节,我们根据数据库表来自动生成基本的查询与更新schema,并能方便的扩展schema,实现我们想来的业务逻辑。设计思路对象定义在apollo-server中是用字符串来做的,而Query与Mutation只能有一个,而我们的定义又会分散在多个文件中,因此只能先以一定的形式把它们存入数组中,在生成schema前一刻再组合。业务逻辑模块模板设计:const customDefs = { textDefs: type ReviseResult { id: Int affectedRows: Int status: Int message: String }, queryDefs: [], mutationDefs: []}const customResolvers = { Query: { }, Mutation: { } }export { customDefs, customResolvers }schema合并算法let typeDefs = [] let dirGraphql = requireDir('../../graphql') //从手写schema业务模块目录读入文件 G.L.each(dirGraphql, (item, name) =&gt; { if (item &amp;&amp; item.customDefs &amp;&amp; item.customResolvers) { typeDefs.push(item.customDefs.textDefs || '') //合并文本对象定义 typeDefObj.query = typeDefObj.query.concat(item.customDefs.queryDefs || []) //合并Query typeDefObj.mutation = typeDefObj.mutation.concat(item.customDefs.mutationDefs || []) //合并Matation let { Query, Mutation, ...Other } = item.customResolvers Object.assign(resolvers.Query, Query) //合并resolvers.Query Object.assign(resolvers.Mutation, Mutation) //合并resolvers.Mutation Object.assign(resolvers, Other) //合并其它resolvers } }) //将query与matation查询更新对象由自定义的数组转化成为文本形式 typeDefs.push(Object.entries(typeDefObj).reduce((total, cur) =&gt; { return total += type ${G.tools.bigCamelCase(cur[0])} { ${cur[1].join(’’)} } }, ''))从数据库表动态生成schema自动生成内容:一个表一个对象;每个表有两个Query,一是单条查询,二是列表查询;三个Mutation,一是新增,二是更新,三是删除;关联表以上篇中的Book与Author为例,Book中有author_id,会生成一个Author对象;而Author表中会生成一个对象列表[Book]mysql类型 =&gt; graphql 类型转化常量定义定义一类型转换,不在定义中的默认为String。const TYPEFROMMYSQLTOGRAPHQL = { int: 'Int', smallint: 'Int', tinyint: 'Int', bigint: 'Int', double: 'Float', float: 'Float', decimal: 'Float',}从数据库中读取数据表信息 let dao = new BaseDao() let tables = await dao.querySql('select TABLE_NAME,TABLE_COMMENT from information_schema.TABLES' + ' where TABLE_SCHEMA = ? and TABLE_TYPE = ? and substr(TABLE_NAME,1,2) &lt;&gt; ? order by ?', [G.CONFIGS.dbconfig.db_name, 'BASE TABLE', 't_', 'TABLE_NAME'])从数据库中读取表字段信息tables.data.forEach((table) =&gt; { columnRs.push(dao.querySql('SELECT COLUMNS.COLUMN_NAME,COLUMNS.COLUMN_TYPE,COLUMNS.IS_NULLABLE,' + 'COLUMNS.CHARACTER_SET_NAME,COLUMNS.COLUMN_DEFAULT,COLUMNS.EXTRA,' + 'COLUMNS.COLUMN_KEY,COLUMNS.COLUMN_COMMENT,STATISTICS.TABLE_NAME,' + 'STATISTICS.INDEX_NAME,STATISTICS.SEQ_IN_INDEX,STATISTICS.NON_UNIQUE,' + 'COLUMNS.COLLATION_NAME ' + 'FROM information_schema.COLUMNS ' + 'LEFT JOIN information_schema.STATISTICS ON ' + 'information_schema.COLUMNS.TABLE_NAME = STATISTICS.TABLE_NAME ' + 'AND information_schema.COLUMNS.COLUMN_NAME = information_schema.STATISTICS.COLUMN_NAME ' + 'AND information_schema.STATISTICS.table_schema = ? ' + 'where information_schema.COLUMNS.TABLE_NAME = ? and COLUMNS.table_schema = ?', [G.CONFIGS.dbconfig.db_name, table.TABLE_NAME, G.CONFIGS.dbconfig.db_name])) })几个工具函数取数据库表字段类型,去除圆括号与长度信息 getStartTillBracket(str: string) { return str.indexOf('(') &gt; -1 ? str.substr(0, str.indexOf('(')) : str }下划线分隔的表字段转化为big camel-case bigCamelCase(str: string) { return str.split('_').map((al) =&gt; { if (al.length &gt; 0) { return al.substr(0, 1).toUpperCase() + al.substr(1).toLowerCase() } return al }).join('') }下划线分隔的表字段转化为small camel-case smallCamelCase(str: string) { let strs = str.split('_') if (strs.length &lt; 2) { return str } else { let tail = strs.slice(1).map((al) =&gt; { if (al.length &gt; 0) { return al.substr(0, 1).toUpperCase() + al.substr(1).toLowerCase() } return al }).join('') return strs[0] + tail } }字段是否以_id结尾,是表关联的标志不以_id结尾,是正常字段,判断是否为null,处理必填typeDefObj[table].unshift(${col[‘COLUMN_NAME’]}: ${typeStr}${col[‘IS_NULLABLE’] === ‘NO’ ? ‘!’ : ‘’}\n)以_id结尾,则需要处理关联关系 //Book表以author_id关联单个Author实体 typeDefObj[table].unshift(“““关联的实体””” ${G.L.trimEnd(col[‘COLUMN_NAME’], ‘_id’)}: ${G.tools.bigCamelCase(G.L.trimEnd(col[‘COLUMN_NAME’], ‘id’))}) resolvers[G.tools.bigCamelCase(table)] = { [G.L.trimEnd(col['COLUMN_NAME'], '_id')]: async (element) =&gt; { let rs = await new BaseDao(G.L.trimEnd(col['COLUMN_NAME'], '_id')).retrieve({ id: element[col['COLUMN_NAME']] }) return rs.data[0] } } //Author表关联Book列表 let fTable = G.L.trimEnd(col['COLUMN_NAME'], '_id') if (!typeDefObj[fTable]) { typeDefObj[fTable] = [] } if (typeDefObj[fTable].length &gt;= 2) typeDefObj[fTable].splice(typeDefObj[fTable].length - 2, 0, “““关联实体集合””"${table}s: [${G.tools.bigCamelCase(table)}]\n) else typeDefObj[fTable].push(${table}s: [${G.tools.bigCamelCase(table)}]\n) resolvers[G.tools.bigCamelCase(fTable)] = { [${table}s]: async (element) =&gt; { let rs = await new BaseDao(table).retrieve({ [col['COLUMN_NAME']]: element.id}) return rs.data } }生成Query查询单条查询 if (paramId.length &gt; 0) { typeDefObj['query'].push(${G.tools.smallCamelCase(table)}(${paramId}!): ${G.tools.bigCamelCase(table)}\n) resolvers.Query[${G.tools.smallCamelCase(table)}] = async (_, { id }) =&gt; { let rs = await new BaseDao(table).retrieve({ id }) return rs.data[0] } } else { G.logger.error(Table [${table}] must have id field.) }列表查询 let complex = table.endsWith('s') ? (table.substr(0, table.length - 1) + 'z') : (table + 's') typeDefObj['query'].push(${G.tools.smallCamelCase(complex)}(${paramStr.join(’, ‘)}): [${G.tools.bigCamelCase(table)}]\n) resolvers.Query[${G.tools.smallCamelCase(complex)}] = async (_, args) =&gt; { let rs = await new BaseDao(table).retrieve(args) return rs.data }生成Mutation查询 typeDefObj['mutation'].push( create${G.tools.bigCamelCase(table)}(${paramForMutation.slice(1).join(’, ‘)}):ReviseResult update${G.tools.bigCamelCase(table)}(${paramForMutation.join(’, ‘)}):ReviseResult delete${G.tools.bigCamelCase(table)}(${paramId}!):ReviseResult ) resolvers.Mutation[create${G.tools.bigCamelCase(table)}] = async (_, args) =&gt; { let rs = await new BaseDao(table).create(args) return rs } resolvers.Mutation[update${G.tools.bigCamelCase(table)}] = async (_, args) =&gt; { let rs = await new BaseDao(table).update(args) return rs } resolvers.Mutation[delete${G.tools.bigCamelCase(table)}`] = async (, { id }) => { let rs = await new BaseDao(table).delete({ id }) return rs }项目地址https://github.com/zhoutk/gels使用方法git clone https://github.com/zhoutk/gelscd gelsyarntsc -wnodemon dist/index.js然后就可以用浏览器打开链接:http://localhost:5000/graphql 查看效果了。小结我只能把大概思路写出来,让大家有个整体的概念,若想很好的理解,得自己把项目跑起来,根据我提供的思想,慢慢的去理解。因为我在编写的过程中还是遇到了不少的难点,这块既要自动化,还要能方便的接受手动编写的schema模块,的确有点难度。 ...

April 13, 2019 · 3 min · jiezi

为什么 GraphQL 是 API 的未来

翻译:疯狂的技术宅https://medium.freecodecamp.o…本文首发微信公众号:前端先锋欢迎关注,每天都给你推送新鲜的前端技术文章自从 Web 开始迅猛发展,对程序员来说开发 API 是一项很艰巨的任务。我们开发 API 的方式必须随着时间的推移而发展,以便我们始终可以开发良好、直观且设计良好的API。在过去几年中,GraphQL 在越来越受到开发者的欢迎。许多公司已经开始采用这种技术来构建他们的API。 GraphQL 是一种由 Facebook 在 2012 年开发并于 2015 年公开发布的查询语言。它已经收到了广泛的关注,并被许多大公司采用,如 Spotify,Facebook,GitHub,NYTimes,Netflix,沃尔玛等。在本系列教程中,我们将研究 GraphQL,了解它是什么,并学习使这种查询语言如此直观和易用的原因是什么。先让我们研究一下 REST 存在的问题,以及 GraphQL 如何解决它们。我们还将了解那些大公司为什么用 GraphQL 去构建API,以及为什么它是 API 的未来。REST很久以前,当我们把 API 的设计从 SOAP 转向 REST 时,认为此举将会为工作提供更多的灵活性。我们不能否认 REST 的运作是良好的,在当时是一个很好的举措。但是随着应用和 Web 变得越来越复杂,API 也会随着这些变化而发展。不过 REST 也确实存在很多问题。让我们看看它们是什么:太多的端点REST 中的每个资源都由端点表示。因此,在实际的程序中,我们最终会为这些资源提供大量端点。如果要发出 GET 请求,则需要具有特定参数并特定于该请求的端点。如果要发出 POST 请求,则需要该请求的另一个端点。但是这有什么问题呢?假设我们正在开发一个像 Facebook 这样的大型社交媒体应用,最终会得到很多端点,这意味着开发和维护这些 API 将花费更多的时间和精力。过度获取和欠缺的信息真正令人烦恼的问题是通过 REST API 会过度获取和欠缺的信息。这是因为 REST API 会始终返回固定的结构。除非我们再去创建一个特定的端点,否则无法准确获取所需的数据。因此如果我们只需要一小部分数据,就必须处理整个对象。例如,如果我们只需要在 REST API 中获取用户的 firstName,lastName 和 age,就无法在不获取整个对象的情况下得到这些数据。信息欠缺也存在问题。如果我们想从两个不同的资源获取数据,就需要分别对两个不同的端点进行调用。在一个巨大的程序中,扩展性会很差,因为在某些情况下我们只需要获取特定的数据,而不是整个对象。假设我们正在开发一个具有 100 个端点的程序。想象一下工作量和产生的代码量。随着时间的推移,开发会变得越来越困难,代码也难以维护,程序员会感到迷茫。版本控制在我看来,REST 中的一个痛点就是版本控制。使用 REST API,通常会看到许多带有 v1 或 v2 的 API。这些在 GraphQL 中并不需要,因为你可以通过添加或删除类型来改进 API。在GraphQL中,你所需要做的就是写新代码。可以编写新类型、查询和修改,而无需维护其他版本的API。因此你将看不到如下所示具有端点的 GraphQL API:https://example.com/api/v1/users/12312https://example.com/api/v2/users/12312为什么 GraphQL 是未来早在2012年,Facebook 在开发移动应用时面临一个问题,这导致他们开发了 GraphQL。这些问题非常普遍,特别是当我们谈论 RESTful API 设计时。如上所述,这些问题是:表现不佳端点过多过度获取或欠缺数据每当我们要增加或删除某些内容时,需要开发另一个版本API 难以理解考虑到许多概念,Facebook 的开发人员开使用了一种更好的方法来设计 API,后来将其命名为 GraphQL。基本上它是 REST 的替代品,做了很多改进。使用 GraphQL,我们可以获得许多新功能,在构建 API 时为你提供强大的功能。下面让我们一个一个地审视它们:单端点根本没有必要构建很多端点!GraphQL 只需要一个端点,通过它我们可以在单个请求中获得尽可能多的数据。基本上 GraphQL 会将你的所有查询、修改和订阅封装在一个端点中,并供你调用。它改善了你的开发周期,因为你不必向两个不同的资源发出请求来获取数据。此外,当我们开发一个大型的应用时,不必再像 REST 一样获得大量端点和代码。我们只需要获得一个端点,并根据需要开发尽可能多的请求即可。正如我上面所说,“单端点”方法使你的 API 能够自我描述,你不再需要再去构建文档,因为你的程序员已经知道应该如何使用。他们只需查看代码即可了解API。我们稍后会详细了解它(本系列的下一篇教程)。看起来很神奇,但这就是 GraphQL!使用 GraphQL,你只能获取所需的数据没有过度获取或未被充分利用的信息,你只获取自己需的数据。还记得我们最初讨论的性能问题吗?不会再像那样了,因为 GraphQL 提高了 API 的性能,特别是在网络连接速度较慢的情况下。GraphQL 使得开发 API 变得容易并保持一致很多人认为 GraphQL 非常复杂,因为它涉及模式和单个端点。但是你一旦开始用它开发 API,会发现它比你想象的要容易得多。当你开发网站或应用时,“单端点” API 会给你很大帮助。它使你的 API 更加能够自我描述,并且无需为它编写大量的文档。如果你并不是把 JavaScript 作为主要语言,那也不是问题。 GraphQL 是一种查询语言,这意味着你可以使用任何自己熟悉的语言。在编写本教程时,GraphQL 支持的语言已经超过了 12 种。GraphQL 是未来GraphQL 是一种开源查询语言,这意味着社区可以为其做出贡献并对加以改进。当 Facebook 将其发布到社区时,得到了大量的认同。现在随着越来越多的程序员用它构建 API,GraphQL 一直在快速增长。但是也有些人一直在问它是否真的要取代 REST,或者成为构建 API 的新方法。起初,我认为 GraphQL 是一个炒作,仅仅是创建 API 的另一种方式。但是当我开始研究它时,发现 GraphQL 具有为现代应用程序创建 API 所需的基本功能,因为它非常适合现今的技术栈。所以如果我要对你说些什么,我会说:是的,GraphQL的确是API的未来。这就是大公司在它身上押注的原因。在2018年11月,GraphQL 与 Linux Foundation 合作创建了一个 GraphQL Foundation。这种查询语言鼓励其开发人员创建更多的文档、工具和语言支持。这将确保 GraphQL 的稳定、中立和可持续发展的未来。因此这也是将 GraphQL 视为 API 的未来的另一个原因。当然 GraphQL 不会立即取代 REST,因为许多应用仍然在使用它,也不可能在一夜之间重写它们。随着越来越多的公司采用 GraphQL,UX 和 DX 都将得到改进。结论GraphQL 的确是API的未来,我们需要了解更多信息。这就是我决定撰写这一系列教程的原因,这些教程将为我们展示如何用好 GraphQL,先从查询和修改开始,然后是订阅和身份验证。在本系列的下一篇教程中,我将深入研究 GraphQL,展示 GraphQL 如何与类型一起工作,并创建我们的第一个查询和修改。所以请继续关注并希望在下一个教程中见到你!本文首发微信公众号:前端先锋欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章欢迎继续阅读本专栏其它高赞文章:12个令人惊叹的CSS实验项目必须要会的 50 个React 面试题世界顶级公司的前端面试都问些什么11 个最好的 JavaScript 动态效果库CSS Flexbox 可视化手册从设计者的角度看 React过节很无聊?还是用 JavaScript 写一个脑力小游戏吧!CSS粘性定位是怎样工作的一步步教你用HTML5 SVG实现动画效果程序员30岁前月薪达不到30K,该何去何从14个最好的 JavaScript 数据可视化库8 个给前端的顶级 VS Code 扩展插件Node.js 多线程完全指南把HTML转成PDF的4个方案及实现 ...

April 12, 2019 · 1 min · jiezi

Graphql实战系列(上)

背景介绍graphql越来越流行,一直想把我的凝胶项目除了支持restful api外,也能同时支持graphql。由于该项目的特点是结合关系数据库的优点,尽量少写重复或雷同的代码。对于rest api,在做完数据库设计后,百分之六十到八十的接口就已经完成了,但还需要配置上api文档。而基于数据库表自动实现graphql,感觉还是有难度的,但若能做好,连文档也就同时提供了。不久前又看到了一句让我深以为然的话:No program is perfect, even the most talented engineers will write a bug or two (or three). By far the best design pattern available is simply writing less code. That’s the opportunity we have today, to accomplish our goals by doing less. so, ready go…基本需求与约定根据数据库表自动生成schema充分利用已经有的支持restful api的底层接口能自动实现一对多的表关系能方便的增加特殊业务,只需要象rest一样,只需在指定目录,增加业务模块即可测试表有两个,book & authorbook表字段有:id, title, author_idauthor表字段有: id, name数据表必须有字段id,类型为整数(自增)或8位字符串(uuid),作为主键或建立unique索引表名为小写字母,使用名词单数,以下划作为单词分隔表关联自动在相关中嵌入相关对象,Book对象增加Author对象,Author对象增加books列表每个表会默认生成两个query,一个是以id为参数进行单条查询,另一个是列表查询;命名规则;单条查询与表名相同,列表查询为表名+s,若表名本身以s结尾,则变s为z桥接库比较与选择我需要在koa2上接入graphql,经过查阅资料,最后聚焦在下面两个库上:kao-graphqlapollo-server-koakao-graphql实现开始是考虑简单为上,试着用kao-graphql,作为中间件可以方便的接入,我指定了/gql路由,可以测试效果,代码如下:import * as Router from ‘koa-router’import BaseDao from ‘../db/baseDao’import { GraphQLString, GraphQLObjectType, GraphQLSchema, GraphQLList, GraphQLInt } from ‘graphql’const graphqlHTTP = require(‘koa-graphql’)let router = new Router()export default (() => { let authorType = new GraphQLObjectType({ name: ‘Author’, fields: { id: { type: GraphQLInt}, name: { type: GraphQLString} } }) let bookType = new GraphQLObjectType({ name: ‘Book’, fields: { id: { type: GraphQLInt}, title: { type: GraphQLString}, author: { type: authorType, resolve: async (book, args) => { let rs = await new BaseDao(‘author’).retrieve({id: book.author_id}) return rs.data[0] } } } }) let queryType = new GraphQLObjectType({ name: ‘Query’, fields: { books: { type: new GraphQLList(bookType), args: { id: { type: GraphQLString }, search: { type: GraphQLString }, title: { type: GraphQLString }, }, resolve: async function (, args) { let rs = await new BaseDao(‘book’).retrieve(args) return rs.data } }, authors: { type: new GraphQLList(authorType), args: { id: { type: GraphQLString }, search: { type: GraphQLString }, name: { type: GraphQLString }, }, resolve: async function (, args) { let rs = await new BaseDao(‘author’).retrieve(args) return rs.data } } } }) let schema = new GraphQLSchema({ query: queryType }) return router.all(’/gql’, graphqlHTTP({ schema: schema, graphiql: true }))})() 这种方式有个问题,前面的变量对象中要引入后面定义的变量对象会出问题,因此投入了apollo-server。但apollo-server 2.0网上资料少,大多是介绍1.0的,而2.0变动又比较大,因此折腾了一段时间,还是要多看英文资料。apollo-server 2.0集成很多东西到里面,包括cors,bodyParse,graphql-tools 等。apollo-server 2.0实现静态schema通过中间件加载,放到rest路由之前,加入顺序及方式请看app.ts,apollo-server-kao接入代码://自动生成数据库表的基础schema,并合并了手写的业务模块import { getInfoFromSql } from ‘./schema_generate’const { ApolloServer } = require(‘apollo-server-koa’)export default async (app) => { //app是koa实例 let { typeDefs, resolvers } = await getInfoFromSql() //数据库查询是异步的,所以导出的是promise函数 if (!G.ApolloServer) { G.ApolloServer = new ApolloServer({ typeDefs, //已经不需要graphql-tools,ApolloServer构造函数已经集成其功能 resolvers, context: ({ ctx }) => ({ //传递ctx等信息,主要供认证、授权使用 …ctx, …app.context }) }) } G.ApolloServer.applyMiddleware({ app })}静态schema试验,schema_generate.tsconst typeDefs = type Author { id: Int! name: String books: [book] } type Book { id: Int! title: String author: Author } # the schema allows the following query: type Query { books: [Post] author(id: Int!): Author }const resolvers = { Query: { books: async function (, args) { let rs = await new BaseDao(‘book’).retrieve(args) return rs.data }, author: async function (, { id }) { let rs = await new BaseDao(‘author’).retrieve({id}) return rs.data[0] }, }, Author: { books: async function (author) { let rs = await new BaseDao(‘book’).retrieve({ author_id: author.id }) return rs.data }, }, Book: { author: async function (book) { let rs = await new BaseDao(‘author’).retrieve({ id: book.author_id }) return rs.data[0] }, },}export { typeDefs, resolvers}项目地址https://github.com/zhoutk/gels使用方法git clone https://github.com/zhoutk/gelscd gelsyarntsc -wnodemon dist/index.js然后就可以用浏览器打开链接:http://localhost:5000/graphql 查看效果了。小结这是第一部分,确定需求,进行了技术选型,实现了接入静态手写schema试验,下篇将实现动态生成与合并特殊业务模型。 ...

April 11, 2019 · 2 min · jiezi

GraphQL 和 Apollo 为什么能帮助你更快地完成开发需求?

在大前端应用的开发过程中,如何管理好数据是一件很有挑战的事情。后端工程师需要聚合来自多个数据源的数据,再分发到大前端的各个端中,而大前端工程师需要在实现用户体验好的视图 (optimistic UI1) 的基础上,需要考虑如何管理端上的状态。在团队中使用 GraphQL 能够很好的解决数据管理的痛点。本文接下来会介绍 GraphQL 声明式(declarative)获取数据的方法,这将简化数据管理的难度,并且提升网络性能。还会介绍 Apollo2 如何通过一系列对开发者体验好的工具,提高工程师的开发效率。译注1:optimistic UI 是一种 UI 设计模式。例如,你在微信上发送消息会直接显示,而不用等到消息的网络请求成功或失败后再显示。optimistic UI 的数据管理很复杂,需要先显示模拟数据,再等待网络请求成功或失败后,再显示真正的数据。通过 Apollo 可以轻易地实现 optimistic UI。译注2:Apollo 是实现,GraphQL 是标准,和 JS/ECMA 的关系一样。开发者体验Apollo 可以帮助团队更快地实现功能上线,因为它对开发者的体验非常好。Apollo 目标是"让各端的数据管理变得简单"(simplify data management across the stack)。通过 Apollo Client、Apollo Server 和 Apollo Engine,以前需要花上一些功夫实现的功能,比如全栈缓存、数据规范化、optimistic UI,现在变得很简单。请求你所要的数据GraphQL 强类型查询语言的特性,使得开发者可以利用牛逼的工具来请求 GraphQL 接口。借助 GraphQL 内省系统(introspection system),开发者可以查询 GraphQL schema 3信息,包括字段和类型。内省系统拥有一些非常炫酷的功能,比如自动生成的文档、代码自动补全等等。译注3:schema 用于描述你所要数据的结构和字段,如: { dogs { id breed image { url } activities { name } } }GraphQL PlaygroundPrisma 团队开发的 GraphQL Playground 工具是一款非常优秀的 IDE,它可以把自定义的 schema 和查询历史自动地生成文档。只要看一下,你就知道 GraphQL API 中有哪些能获取到的数据,而不用研究后端代码或了解数据来源。Apollo Server 2.0 内置了 GraphQL Playground,更方便你浏览 schema 和执行查询命令。Apollo DevToolsApollo DevTools 是 Chrome 的扩展程序,可以查询 Apollo 的前端缓存(Cache),记录查询(Queries)和变更(Mutations)。你还可以使用 Apollo DevTools 中的 GraphiQL 来方便地测试前端查询。简化前端代码如果你使用过 REST 和状态管理库,如 Redux,为了发一个网络请求,你需要写 action creators、reducers、mapStateToProps 并集成中间件。使用 Apollo Client,你再也不用关系这些东西。Apollo Client 解决了一切,你只需要专注于查询,而不需要写一堆状态管理的代码。import ApolloClient from “apollo-boost”;const client = new ApolloClient({ uri: “https://dog-graphql-api.glitch.me/graphql"});有团队声称他们切换成 Apollo Client 后,删除了上千行状态管理代码和一堆复杂逻辑。这得益于 Apollo Client 不仅支持远程数据管理,还支持本地数据管理, Apollo 缓存就是当前应用全局状态的单一事实来源。现代化的工具Apollo platform4 可以让团队使用现代化的工具,帮忙他们快速发现错误、查看 API、开发具有挑战的缓存功能。译注4:Apollo platform 是云平台。Apollo 在本文中有两层含义,首先 Apollo 是 GraphQL 的一个开源实现,其次 Apollo 是开发 Apollo platform 、Apollo Client 、Apollo Server 等产品的公司。Apollo Engine 是 GraphQL 生态系统中唯一可以为你的 API 提供监控和分析的工具。Engine 可以显示每个 resolver5 的埋点指标,可以帮忙你定位错误, 可以分析 schema 中请求的每个字段的分布频率。 你还可以将这些数据传输到你正在用的其他分析平台,如 DataDog,并在某些数据超过报警阙值设置时进行报警。译注5:resolver 处理返回字段的函数声明式数据获取使用 GraphQL 的一个主要优点是它有声明式数据获取的能力,不需要前端请求多个接口,不需要手动的聚合数据,只需要你精确地描述你所要的数据,然后 GraphQL 就会将你要的数据返回给你。而使用 REST ,你需要调用每一个接口,并过滤出你要的数据,然后将过滤后的数据构造成组件所需要的结构。GET /api/dogs/breedsGET /api/dogs/imagesGET /api/dogs/activitiesREST 的方法不仅不好使,而且容易出错,难以跨平台重用逻辑。对比一下 GraphQL 声明式的方式:const GET_DOGS = gql query { dogs { id breed image { url } activities { name } } };在上面,我们定义了我们想要从服务端获取的对象的结构。GraphQL 负责组合和过滤数据,同时返回我们想要的数据字段和结构。如何使用 GraphQL 查询?Apollo Client 构建了 GraphQL 声明式请求数据的方法。在 React 应用中,获取数据、跟踪加载和错误状态以及更新 UI 的所有逻辑,都封装在一个 Query 组件中。这种封装方式使数据获取组件和展示组件很容易的组合在一起。让我们看看,如何在 React 应用中使用 Apollo Client 获取 GraphQL 数据:const Feed = () => ( {/* 数据获取组件 Query*/} <Query query={GET_DOGS}> {/* 展示组件:由 Error、Fetching、DogList 等组成的函数组件 /} {({ loading, error, data }) => { if (error) return <Error /> if (loading || !data) return <Fetching />; return <DogList dogs={data.dogs} /> }} </Query>);Apollo Client 管理整个请求的周期,从请求开始到请求结束,包括为你跟踪加载和错误状态。这里不用设置中间件,不用写模板代码,不用重构的数据结构,不用关心请求缓存。你所需要做的就是描述你组件要的数据,然后让 Apoolo Client 去完成那些繁重的工作。当你使用 Apollo Client 时,你会发现你能删除很多不需要的数据管理方面的代码。具体能够删除多少行代码,要根据你项目的情况来判断,但有些团队声称他们删除了数千行代码。要了解更多 Apollo Client 的牛逼功能,例如 optimistic UI、重新获取、分页获取,请查看我们的状态管理指南。提升网络性能在许多情况下,在现有的 REST 接口层之上增加 GraphQL API 层,可以提高你 App 的网络性能,特别是在网络差的情况下。虽然,你应该通过网络性能监控来衡量 GraphQL 如何影响你的 App,但大家通常认为 GraphQL 通过避免客户端与服务端的往返通讯(round trips),和减少请求数据的大小来提升网络性能的。更少的请求数据因为从服务端返回的响应中只包含你指定的查询数据,所以 GraphQL 相对于 REST 可以显著地减少请求数据的大小。让我们看看前面文章中的例子:const GET_DOGS = gql query { dogs { id breed image { url } activities { name } } };GraphQL 服务响应中只包括 dogs 对象的 id、breed、image、activities 字段,即便 REST 层的接口 dogs 是带有 100 个字段的对象也是如此,所有多余的字段都将在返回给客户端之前过滤掉。避免往返通讯(round trips)由于每个 GraphQL 请求只返回一个响应,使用 GraphQL 可以帮助你避免客户端到服务端的往返通讯。使用 REST,请求一个资源就是一次往返通讯,往返通讯会快速地增加。如果你请求要列表中的每一项,每一项都需要一次往返,每一项中的每个资源也需要一次往返,总次数就是二者的乘积6,这就导致了请求时间过长。 译注6:极端 REST 例子,列表长度 N,每一项 3 个资源,请求次数就是 3NGET /api/dogs/breedsGET /api/dogs/imagesGET /api/dogs/activities使用 GraphQL,每个查询代表一次往返通讯。如果你希望进一步的减少往返,你可以实现查询批处理(query batching),将多个查询封装到单个请求中。产品案例虽然 GraphQL 规范是由 Facebook 在 2015 年公布的,但是自 2012 年以来,GraphQL 就是 Facebook 移动应用开发的重要组成部分。在 Apollo 团队,我们发现 GraphQL 为我们现有方案中遇到的很多问题提供了出色的解决方案,现在我们用它来优化我们的技术基础设施。几年来,我们和开源社区、客户、合作伙伴一起,为开源项目 Apollo 带了了诸多创新。我们很骄傲,Apollo 适用于各类公司,从创业公司到大型企业。除了我们自己的经验,我们还收到了积极地在生产环境中使用 Apollo GraphQL 的企业客户的广泛反馈、贡献和支持。一些最值得借鉴的案例是:The New York Times(https://open.nytimes.com/the-…: 学习 The New York Times 如何从 Relay 切换到 Apollo,实现他们 App 的 SSR 和持久化 queries。Airbnb(https://medium.com/airbnb-eng…: Airbnb 在 Apollo 平台上下了重注,去强化他们微服务的数据层。Express(https://dev-blog.apollodata.c…:使用易上手的 Apollo 分页功能,优化我们团队的关键应用。Major League Soccer(https://dev-blog.apollodata.c…: 团队的数据管理工具从 Redux 切换到了 Apollo,帮忙他们删除了几乎所有的 Redux 代码。Expo(https://dev-blog.apollodata.c…: 使用 Apollo 开发 React Native App 使得团队可以专注于改善产品功能,而不是写数据抓取的逻辑。KLM(https://youtu.be/T2njjXHdKqw): 学习 KLM 团队如何使用 GraphQL 和 Apollo 扩展他们的 Angular app。 ...

March 29, 2019 · 2 min · jiezi

NestJS 集成graphql grpc 分布式实践

前言: 为了学习nestjs graphql grpc 微服务方面的知识,具体grpc和graphql的语法再之后在做详细分析1 创建项目npm i -g @nestjs/clinest new project-name2 添加graphql创建graphql-config.service.ts文件,用于graphql的配置及编写过滤器的逻辑@Injectable()export class GraphQLConfigService implements GqlOptionsFactory { constructor() {} createGqlOptions(): GqlModuleOptions { return { typePaths: [join(process.cwd(), “./graphqls/*.graphql”)], // 配置的graphql文件地址 installSubscriptionHandlers: true, definitions: { path: join(process.cwd(), “src/graphql.schema.ts”), // 解析之后的文件地址 outputAs: “class” }, context: async ({ req }) => { // 过滤器 let user = Jwt.verifyToken(req.headers.authorization); // 业务逻辑 return { user }; } }; }}添加进app.module.ts里@Module({ imports: [ GraphQLModule.forRootAsync({ imports: [ApplicationModule], useClass: GraphQLConfigService }), ],})export class ApplicationModule {}创建文件xxx.resolvers.ts @Query(‘getUser’) async getUser() { return {}; }3 添加grpc首先,创建一个子项目xxx子项目创建grpc.options.ts文件,用于init连接的配置export const grpcClientOptions: ClientOptions = { transport: Transport.GRPC, options: { url: “localhost:50051”, // 服务地址 package: “xxx”, protoPath: join(__dirname, ‘./xxx.proto’), },};创建接口, 注意这里的首字母会被自动装为大写 @GrpcMethod(“UserService”) async addUser(data: User): Promise<any> { return data }在main.ts引入import { grpcClientOptions } from ‘./grpc.options’;async function bootstrap() { const app = await NestFactory.create(AppModule); app.connectMicroservice(grpcClientOptions); await app.startAllMicroservicesAsync();}bootstrap();其他微服务或是apigateway调用是创建一个 const grpcClientOptions: ClientOptions = { transport: Transport.GRPC, options: { url: grpcServe.user.url, package: grpcServe.user.package, protoPath: join(__dirname, ‘../../common/proto/user.proto’), },};@Injectable()export class ClentServe { constructor() {} @Client(grpcClientOptions) public readonly client: ClientGrpc;} ...

March 13, 2019 · 1 min · jiezi

GraphQL基金会宣布与联合开发基金会合作推动开源和开放标准

新成员推进GraphQL规范,以扩展GraphQL生态系统,并加速API开发和消费的开源和开放标准加利福尼亚州半月湾 - 开源领导者峰会 - 2019年3月12日 - GraphQL基金会是GraphQL社区加速周围生态系统开发的中立家园,今天宣布与JDF(Joint Development Foundation,联合开发基金会)合作,该基金会最近加入了Linux基金会,以推动开源和标准的采用,继续开发GraphQL规范。GraphQL基金会鼓励广泛的团队在供应商中立的活动、文档、工具和对数据查询语言的支持方面,做出贡献、管理和共享投资。以下公司Apollo、AWS、Butterfly Network、Dgraph Labs、Facebook、Gatsby、GraphZen、Hasura、IBM、Intuit、Neo4j、Novvum、PayPal、Pipefy、Salsify、Solo.io和Thicit将以成员方式加入设计更有效的API,推动GraphQL作为行业规范。GraphQL每天在Facebook提供数千亿的API调用,在2012年开发了这项技术,并在去年帮助GraphQL加入Linux基金会方面发挥了不可或缺的作用。今天,几乎所有主流编程语言都通过各种开源软件库提供GraphQL支持。GraphQL是第一个受益于JDF和Linux Foundation协作的Linux Foundation项目,JDF为开源项目提供了开放规范标准化的快捷途径。开发者将拥有一个开放的GraphQL规范和开源软件实现,可用于设计符合要求的API。“我们很高兴正式欢迎新成员并与他们密切合作,以建立和支持全球GraphQL生态系统。我们很高兴GraphQL规范将继续通过JDF和Linux Foundation合作伙伴关系发展。通过更简单、更快捷的方式来创建和推进标准,开发者可以专注于创建对世界各地社区产生更大影响的应用程序。”GraphQL共同创建者Lee Byron说。GraphQL对于API开发很重要,因为它允许单个API请求中的嵌套对象,传统上需要多个API请求。GraphQL规范、GraphQL.js实现参考、DataLoader库和GraphiQL开发者工具是GraphQL 基金会支持的技术项目。随着应用程序开发转向微服务架构,重点是灵活性和上市速度,GraphQL等工具正在重新定义API设计和客户端服务器交互,以改善开发者体验、提高开发者的工作效率并最大限度地减少传输的数据量。GraphQL使跨平台和移动开发更加简单,多种编程语言的可用性在多个平台,如Web、iOS、Android、嵌入式和物联网应用程序中具有一致性和共同特征。Linux基金会和Facebook开源团队利用JDF经过验证的框架为规范创建了一个轻量级的治理结构,允许社区快速启动中立协作。“我们很高兴看到GraphQL和JDF(联合开发基金会)联合起来,并迅速开展工作以推进开放标准。”Linux基金会执行董事Jim Zemlin说。“与JDF合作,GraphQL社区能够利用整套基础设施,比以往更快、更灵活地创建和管理开放标准。这使开发者能够继续打破障碍,实现应用程序开发的现代化。““我们非常高兴能与Linux基金会密切合作,为基于规范的合作创建这种新颖的方法。”Facebook开源团队Michael Cheng表示。“通过为开源社区提供标准化和培育开源实施的简化途径,这种策略调整有利于GraphQL开发者、企业贡献者和最终用户,他们需要两种成果才能取得成功。”“我们期待与GraphQL基金会密切合作,我们期待今年许多其他Linux基金会项目与我们合作,以加快规范和标准制定,以推进他们的使命并推动创新技术的创造。”JDF总裁David Rudin说。KubeCon + CloudNativeCon + Open Source Summit大会日期:会议日程通告日期:2019 年 4 月 10 日会议活动举办日期:2019 年 6 月 24 至 26 日KubeCon + CloudNativeCon + Open Source Summit赞助方案KubeCon + CloudNativeCon + Open Source Summit多元化奖学金现正接受申请KubeCon + CloudNativeCon和Open Source Summit即将首次合体落地中国KubeCon + CloudNativeCon + Open Source Summit购票窗口,立即购票!CNCF邀请你加入最终用户社区

March 13, 2019 · 1 min · jiezi

GraphQL 从入门到实践

本文首先介绍了 GraphQL,再通过 MongoDB + graphql + graph-pack 的组合实战应用 GraphQL,详细阐述如何使用 GraphQL 来进行增删改查和数据订阅推送,并附有使用示例,边用边学印象深刻~如果希望将 GraphQL 应用到前后端分离的生产环境,请期待后续文章。本文实例代码:Github0. 什么是 GraphQLGraphQL 是一种面向数据的 API 查询风格。传统的 API 拿到的是前后端约定好的数据格式,GraphQL 对 API 中的数据提供了一套易于理解的完整描述,客户端能够准确地获得它需要的数据,没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。1. 概述前端的开发随着 SPA 框架全面普及,组件化开发也随之成为大势所趋,各个组件分别管理着各自的状态,组件化给前端仔带来便利的同时也带来了一些烦恼。比如,组件需要负责把异步请求的状态分发给子组件或通知给父组件,这个过程中,由组件间通信带来的结构复杂度、来源不明的数据源、不知从何订阅的数据响应会使得数据流变得杂乱无章,也使得代码可读性变差,以及可维护性的降低,为以后项目的迭代带来极大困难。试想一下你都开发完了,产品告诉你要大改一番,从接口到组件结构都得改,后端也骂骂咧咧不愿配合让你从好几个 API 里取数据自己组合,这酸爽 ????在一些产品链复杂的场景,后端需要提供对应 WebApp、WebPC、APP、小程序、快应用等各端 API,此时 API 的粒度大小就显得格外重要,粗粒度会导致移动端不必要的流量损耗,细粒度则会造成函数爆炸 (Function Explosion);在此情景下 Facebook 的工程师于 2015 年开源了 GraphQL 规范,让前端自己描述自己希望的数据形式,服务端则返回前端所描述的数据结构。简单使用可以参照下面这个图:比如前端希望返回一个 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 TypeGraphQL 的操作类型可以是 query、mutation 或 subscription,描述客户端希望进行什么样的操作query 查询:获取数据,比如查找,CRUD 中的 Rmutation 变更:对数据进行变更,比如增加、删除、修改,CRUD 中的 CUDsubstription 订阅:当数据发生更改,进行消息推送这些操作类型都将在后文实际用到,比如这里进行一个查询操作query { user { id }}2.2 对象类型和标量类型 Object Type & Scalar Type如果一个 GraphQL 服务接受到了一个 query,那么这个 query 将从 Root Query 开始查找,找到对象类型(Object Type)时则使用它的解析函数 (Resolver) 来获取内容,如果返回的是对象类型则继续使用解析函数获取内容,如果返回的是标量类型(Scalar Type)则结束获取,直到找到最后一个标量类型。对象类型:用户在 schema 中定义的 type标量类型: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 … }}解析函数接受四个参数,分别为parent:当前上一个解析函数的返回值args:查询中传入的参数context:提供给所有解析器的上下文信息info:一个保存与当前查询相关的字段特定信息以及 schema 详细信息的值解析函数的返回值可以是一个具体的值,也可以是 Promise 或 Promise 的数组。一些常用的库可以帮省略一些简单的解析函数,比如一个字段没有提供对应的解析函数时,会从上层返回对象中读取和返回和这个字段同名的属性。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”: “…”, “operationName”: “…”, “variables”: { “myVariable”: “someValue”, … }}返回的格式一般也是 JSON 体# 正确返回{ “data”: { … }}# 执行时发生错误{ “errors”: [ … ]}如果执行时发生错误,则 errors 数组里有详细的错误信息,比如错误信息、错误位置、抛错现场的调用堆栈等信息,方便进行定位。3. 实战这里使用 MongoDB + graph-pack 进行一下简单的实战,并在实战中一起学习一下,详细代码参见 Github MongoDB 是一个使用的比较多的 NoSQL,可以方便的在社区找到很多现成的解决方案,报错了也容易找到解决方法。graph-pack 是集成了 Webpack + Express + Prisma + Babel + Apollo-server + Websocket 的支持热更新的零配置 GraphQL 服务环境,这里将其用来演示 GraphQL 的使用。3.1 环境部署首先我们把 MongoDB 启起来,这个过程就不赘述了,网上很多教程;搭一下 graph-pack 的环境npm i -S graphpack在 package.json 的 scripts 字段加上:“scripts”: { “dev”: “graphpack”, “build”: “graphpack build”}创建文件结构:.├── src│ ├── db // 数据库操作相关│ │ ├── connect.js // 数据库操作封装│ │ ├── index.js // DAO 层│ │ └── setting.js // 配置│ ├── resolvers // resolvers│ │ └── index.js│ └── schema.graphql // schema└── package.json这里的 schema.graphql 是 2.3 节的示例代码,其他实现参见 Github,主要关注 src/db 、src/resolvers、src/schema.graphql 这三个地方src/db:数据库操作层,包括 DAO 层和 Service 层(如果对分层不太了解可以看一下最后一章)src/resolvers:Resolver 解析函数层,给 GraphQL 的 Query、Mutation、Subscription 请求提供 resolver 解析函数src/schema.graphql:Schema 层然后 npm run dev ,浏览器打开 http://localhost:4000/ 就可以使用 GraphQL Playground 开始调试了,左边是请求信息栏,左下是请求参数栏和请求头设置栏,右边是返回参数栏,详细用法可以参考 Prisma 文档 3.2 Query首先我们来试试 hello world,我们在 schema.graphql 中写上 Query 的一个入口 hello,它接受 String 类型的返回值# src/schema.graphql# Query 入口type Query { hello: String}在 src/resolvers/index.js 中补充对应的 Resolver,这个 Resolver 比较简单,直接返回的 String// src/resolvers/index.jsexport default { Query: { hello: () => ‘Hello world!’ }}然后我们在 Playground 中进行 Query# 请求query { hello}# 返回值{ “data”: { “hello”: “Hello world!” }}这里拿到了 hello world 返回值,hello world 总是如此愉快,下面我们来进行稍微复杂一点的查询一个查询入口 users 查找所有用户列表,返回一个不可空但长度可以为 0 的数组,数组中如果有元素,则必须为 User类型;另一个查询入口 user 接受一个字符串,查找 ID 为这个字符串的用户,并返回一个 User 类型的可空字段# src/schema.graphql# Query 入口type Query { user(id: String): User users: [User]!}type User { id: ID! name: String! age: Int email: String!}增加对应的 Resolver// src/resolvers/index.jsimport Db from ‘../db’export default { Query: { user: (parent, { id }) => Db.user({ id }), users: (parent, args) => Db.users({}) }}这里的两个方法 Db.user、Db.users 分别是查找对应数据的函数,返回的是 Promise,如果这个 Promise 被 resolve,那么被 resolve 的数据将被作为结果返回。然后进行一次查询就可以查找我们所希望的所有信息# 请求query { user(id: “2”) { id name email age } users { id name }}# 返回值{ “data”: { “user”: { “id”: “2”, “name”: “李四”, “email”: “mmmmm@qq.com”, “age”: 18 }, “users”: [{ “id”: “1”, “name”: “张三” },{ “id”: “2”, “name”: “李四” }] }}注意这里,返回的数组只希望拿到 id、name 这两个字段,因此 GraphQL 并没有返回多余的数据,怎么样,是不是很贴心呢3.3 Mutation知道如何查询数据,还得了解增加、删除、修改,毕竟这是 CRUD 工程师必备的几板斧,不过这里只介绍比较复杂的修改,另外两个方法可以看一下 Github 上。# src/schema.graphql# Mutation 入口type Mutation { updateUser(id: ID!, name: String, email: String, age: Int): User!}type User { id: ID! name: String! age: Int email: String!}同理,Mutation 也需要 Resolver 来处理请求// src/resolvers/index.jsimport Db from ‘../db’export default { Mutation: { updateUser: (parent, { id, name, email, age }) => Db.user({ id }) .then(existUser => { if (!existUser) throw new Error(‘没有这个id的人’) return existUser }) .then(() => Db.updateUser({ id, name, email, age })) }}Mutation 入口 updateUser 拿到参数之后首先进行一次用户查询,如果没找到则抛个错,这个错将作为 error 信息返回给用户,Db.updateUser 这个函数返回的也是 Promise,不过是将改变之后的信息返回# 请求mutation UpdataUser ($id: ID!, $name: String!, $email: String!, $age: Int) { updateUser(id: $id, name: $name, email: $email, age: $age) { id name age }}# 参数{“id”: “2”, “name”: “王五”, “email”: “xxxx@qq.com”, “age”: 19}# 返回值{ “data”: { “updateUser”: { “id”: “2”, “name”: “王五”, “age”: 19 } }}这样完成了对数据的更改,拿到了更改后的数据,并且给定希望返回哪些字段。### 3.4 SubscriptionGraphQL 还有一个有意思的地方就是它可以进行数据订阅,当前端发起订阅请求之后,如果后端发现数据改变,可以给前端推送实时信息,我们用一下看看照例,首先在 Schema 中定义 Subscription 的入口# src/schema.graphql# Subscription 入口type Subscription { subsUser(id: ID!): User}type User { id: ID! name: String! age: Int email: String!}然后补充上它的 Resolver// src/resolvers/index.jsimport Db from ‘../db’const { PubSub, withFilter } = require(‘apollo-server’)const pubsub = new PubSub()const USER_UPDATE_CHANNEL = ‘USER_UPDATE’export default { Mutation: { updateUser: (parent, { id, name, email, age }) => Db.user({ id }) .then(existUser => { if (!existUser) throw new Error(‘没有这个id的人’) return existUser }) .then(() => Db.updateUser({ id, name, email, age })) .then(user => { pubsub.publish(USER_UPDATE_CHANNEL, { subsUser: user }) return user }) }, Subscription: { subsUser: { subscribe: withFilter( (parent, { id }) => pubsub.asyncIterator(USER_UPDATE_CHANNEL), (payload, variables) => payload.subsUser.id === variables.id ), resolve: (payload, variables) => { console.log(’???? 接收到数据: ‘, payload) } } }}这里的 pubsub 是 apollo-server 里负责订阅和发布的类,它负责收到订阅的时候返回一个异步迭代器,并且在后端觉得需要发布订阅的时候向前端发布 payload,这里的 withFilter 的作用是过滤掉不需要的订阅消息,详细用法参照订阅过滤器。首先我们发布一个订阅请求# 请求subscription subsUser($id: ID!) { subsUser(id: $id) { id name age email }}# 参数{ “id”: “2” }然后我们用刚刚的数据更新操作来进行一次数据的更改,那么我们将获取并打印出 pubsub.publish 发布的 payload,这样就完成了数据订阅。在 graph-pack 中数据推送是基于 websocket 来实现的,可以在通信的时候打开 Chrome DevTools 看一下。4. 总结目前前后端的结构大概如下图。后端通过 DAO 层与数据库连接,服务于主要处理业务逻辑的 Service 层,为 Controller 层提供数据源并产出 API;前端通过浏览器 URL 进行路由命中获取目标视图状态,而页面视图是由组件嵌套组成,每个组件维护着各自的组件级状态,一些稍微复杂的应用还会使用集中式状态管理的工具,比如 Vuex、Redux、Mobx 等。前后端只通过 API 来交流,这也是现在前后端分离开发的基础。如果使用 GraphQL,那么后端将不再产出 API,而是将 Controller 层维护为 Resolver,并且和前端维护一套 Schema,这个 Schema 将用来生成接口文档,前端直接通过 Schema 或生成的接口文档来进行自己期望的请求。经过几年一线开发者的填坑,已经有一些不错的工具链可以使用于开发与生产,很多语言也提供了对 GraphQL 的支持,比如 JavaScript/Nodejs、Java、PHP、Ruby、Python、Go、C# 等。一些比较有名的公司比如 Twitter、IBM、Coursera、Airbnb、Facebook、Github、携程等,内部或外部 API 从 RESTful 转为了 GraphQL 风格,特别是 Github,它的 v4 版外部 API 只使用 GraphQL。据一位在 Twitter 工作的大佬说硅谷不少一线二线的公司都在想办法转到 GraphQL 上,但是同时也说了 GraphQL 还需要时间发展,因为将它使用到生产环境需要前后端大量的重构,这无疑需要高层的推动和决心。正如尤雨溪所说,为什么 GraphQL 两三年前没有广泛使用起来呢,可能有下面两个原因:GraphQL 的 field resolve 如果按照 naive 的方式来写,每一个 field 都对数据库直接跑一个 query,会产生大量冗余 query,虽然网络层面的请求数被优化了,但数据库查询可能会成为性能瓶颈,这里面有很大的优化空间,但并不是那么容易做。FB 本身没有这个问题,因为他们内部数据库这一层也是抽象掉的,写 GraphQL 接口的人不需要顾虑 query 优化的问题。GraphQL 的利好主要是在于前端的开发效率,但落地却需要服务端的全力配合。如果是小公司或者整个公司都是全栈,那可能可以做,但在很多前后端分工比较明确的团队里,要推动 GraphQL 还是会遇到各种协作上的阻力。大约可以概括为性能瓶颈和团队分工的原因,希望随着社区的发展,基础设施的完善,会渐渐有完善的解决方案提出,让广大前后端开发者们可以早日用上此利器。网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出参考:GraphQL | 一种为你的 API 而生的查询语言JSON-RPC 2.0 规范 - wiki . leozvcGraphQL 为何没有火起来? - 尤雨溪的回答 - 知乎GraphQL什么鬼 | kazaff’s blog ...

March 12, 2019 · 5 min · jiezi

GraphQL学习过程应该是这样的

记录一个从枯燥学习 GraphQL 的过程,到发现项目 Gitter,模仿项目 Github-Trending-API,最后做一个自己的学习项目 Github-Trending-GraphQL。 一开始我是这样想的,最后我是这样做的,复盘整个学习过程。 准备学习graphql 是什么? 在之前的项目中我们主要使用 graphql 来做已有接口数据的合并,这个主要处理已有 rest 相关服务接口的情况下,我们做了一个中间数据处理层。 最近在思考团队服务项目开发的时候,因为在开发中如果基于 rest 接口来开发的会,会定义很多路由。为了偷懒不去定义路由,于是决定在项目中使用 graphql (其实只是为了装B,我在项目中用了最新的XX技术),中间还有一些其他的思考。几个概念Graphql 模型有三种类型的操作。Query查询数据(R)。# standardquery { field}# shorthand{ fields}Mutation新增、更新或删除数据(CUD)。mutation { do( arguments ) { fields }}Objects表示可以访问的资源。# Repository 包含项目的内容 # Implements # Connections # FieldsImplements学不动了,省略….受其它项目启发在枯燥的文档学习过程中,中间看到一个博客是推荐自己的小程序 gitter,出于习惯抓了一下小程序的请求,发现了趋势排行是通过 github-trending-api.now.sh 获取的数据,接着就找到了这个 API 对应的项目 github-trending-api。 在这之前我也看过几次 GitHub GraphQL API,只是趋于时间与其他因素(懒),一直没有使用落实到实际的项目中。发现官方没有提供 Trending API,github-trending-api 项目新增了 V3 中的Trending API,我是不是可以模仿该项目提供一个 GraphQL API。 带着两个目的开始一个新项目:学习 GraphQL做一个开源项目初始化项目最简单的实现方式就是提供一个 GraphQL server,然后直接请求 github-trending-api.now.sh 。这种用法对于项目已有微服务的团队,可以利用中间服务层来合并数据请求,以及嵌套数据查询等。 GraphQL server 使用的是 Apollo Server,用它来创建一个 Node 服务,定义好 Schema,增加 resolver 解析函数。Type 如何定义在一开始学习的基础只是派上用场,GitHub Trending 主要提供两个方面,一个是 Repository ,另外一个是 Developer。type Repository { author: String contributors: [Contributor] currentPeriodStars: Int description: String forks: Int language: Lang name: String stars: Int url: String}Repository 中除了基本的 scalar type 还有两个是 contributor 和 language,一个数组数据,一个是对象,继续细分类型下去就得到了type Contributor { avatar: String url: String username: String}type Lang { name: String color: String}Developer 分析数据后一样得到一个数据结构type Developer { avatar: String name: String repository: RepositoryMini username: String url: String}其中项目仓库是一个对象数据,细分下来可以得到一个type RepositoryMini { description: String name: String url: String}Query 如何定义定义好了基本数据类型 Repository 和 Developer 以后,需要对外提供一个统一的 Query,于是得到了一个新的根数据类型type Query { repositories: [Repository], developers: [Developer]}实际的查询趋势过程中我们还会增加参数,一个参数是 language,一个参数 since,其中 since 只能取 daily、 weekly、 monthly ,但实际也能取其它值,只是默认的还是 daily。修改后得到了下面的结果type Query { repositories(language: String, since: String): [Repository], developers(language: String, since: String): [Developer]}如果要验证 since 只能取三个值中的一直,需要新增一个枚举类型type Query { repositories(language: String, since: Since): [Repository], developers(language: String, since: Since): [Developer]}enum Since { daily weekly monthly}如何优化 Query上述写法实际过程中可能还会有这样一个问题,如果要同时查询获得 Repository 和 Developer 的数据,需要按照筛选条件查询的适合,需要重复传递参数,再提升一下这两个类型实际是属于类型 Trending 的。新增一个类型type Trending { repositories: [Repository] developers: [Developer]}根查询 Query 也可以修改一下了type Query { trending(language: String, since: String): Trending}客户端发起查询请求按照最终我们定义好的数据结构,我们可以发起一个这样的 query{ Trending(language: “javascript”, since: “daily”) { repositories { name author description language { name color } forks stars contributors { avatar url username } currentPeriodStars url } developers { avatar name repository { url name description } username url } }}如果把 language 和 since 定义在 variables 中,写法就变成了下面这样# 以下请求只获取了趋势仓库名称# queryquery getTrending($language: String, $since: String) { trending(language: $language, since: $since) { repositories { name } }}# variables{ “language”: “javascript”, “since”: “daily”}query 和 variables 会作为 request payload 放置在 body 中,其中把自定义的操作方法 operationName 设置为 getTrendingfetch(“https://trending.now.sh”, { “credentials”: “omit”, “headers”: { “accept”: “/”, “accept-language”: “zh-CN,zh;q=0.9,en;q=0.8”, “content-type”: “application/json” }, “referrer”: “http://localhost:4000/”, “referrerPolicy”: “no-referrer-when-downgrade”, “body”: “{"operationName":"getTrending","variables":{"language":"javascript","since":"daily"},"query":"query getTrending($language: String, $since: String) {\n trending(language: $language, since: $since) {\n repositories {\n name\n }\n }\n}\n"}”, “method”: “POST”, “mode”: “cors”});服务端解析请求这里用的是 Apollo server,服务收到请求以后,会解析 body 参数。会按照嵌套依次调用 resolver 处理业务逻辑,首先会进入 trending ,接着同时执行 repository 和 developer。 按照根查询定义好的数据结构,tending 解析器会收到两个参数,language 和 since。repository 和 developer 也要使用这两个参数如何处理呢?// resolver{ Query: { trending(parent, args, context, info) { // args => { language: ‘’, since: ’’ } // parent 参数是可以接收到上层解析器的结果,我们可以把 trending 中收到的数据传递给子解析器 return { language, since } } }, Trending: { repositories(parent, args, context, info) { // parent => { language: ‘’, since: ’’ } }, developer(parent, args, context, info) { // parent => { language: ‘’, since: ’’ } }, }}解析器中需要做什么?解析器按照前文分析的数据,我们可以直接请求 github-trending-api.now.sh 数据接口拿到数据,这里我们本着学习为目的,GitHub Trending 是通过 SSR 输出的页面,数据只能自己分析网页,抓取html页面以后分析页面结构获得自己需要的数据。export async function fetchRepository() { // 分析html}export async function fetchDeveloper() { // 分析html}export async function fetchLanguage() { // 分析html}具体的分析 html 过程不做分析,使用了 cheerio,用法类似 JQuery。这中间也会有一些需要注意的问题请求过程很慢。 每次请求都会再次请求 Github Trending 的页面,然后还要分析页面,这个过程其实是比较费时的。我们如果把请求分析后的数据按照查询条件缓存起来,下一次请求直接就从缓存中拿数据,这样就快很多。(仓库和开发者趋势会隔段时间更新,我们缓存一小时;语言变化小,我们缓存了一天的时间)语言包缓存。 请求仓库和开发者的适合,检测语言缓存是否存在,不存在先缓存一次,后续再次请求仓库和开发者或者直接请求语言包就会直接命中缓存有了缓存就可能出现缓存失效的问题,我们新增一个刷新缓存的方法,可以按照指定键名来更新缓存,也可以不传递参数清理全部缓存。如何清理缓存?GraphQL 根处理方法除了 Query ,还有一个 Mutation。对应到的数据库增删改查上面的话,Query 对应的是 R,Mutation 对应的是 CUD。我们要新增的 refresh 的操作是删除缓存,主要针对仓库和开发者缓存,清理以后我们只关心成功失败与否,所以这里我们可以返回一个布尔值type Mutation { refresh(key: String, language: String, since: String): Boolean}解析器中也需要添加对应的处理方法{ Mutation: { refresh(parent, args, context, info) { // do something } }}回顾一下从一开始的需求分析,我们需要开发一个 Github Trending GraphQL API。我们利用了之前学习的 GraphQL 的基础知识,也熟悉了 GraphQL 的工具 Apollo Server,很方便的开发出了对应的API,后续为了优化请求,我们新增了缓存策略,以及清除缓存策略。 到这里我们的项目 github-trending-graphql 就可以提交到 GitHub 仓库中了,对于一个完美的开源项目还有很多事情要做,但是对于一个 GraphQL 的示例差不多已经可以使用了。 一上来就直接看代码是枯燥的,于是我们还需要部署一个 Demo,这样带着使用来熟悉就更容易让人理解了。如何简单的部署 Demo 又成为了一个问题?如何部署示例trending.now.sh 的部署看域名应该就能猜到使用的是 now 的无服务部署方式。使用方式文档已经讲述的很清楚了。但这中间也还是需要注意一些细节对于项目部署,我们需要首先在项目根目录建立一个 now.json{ “version”: 2, “alias”: [“trending.now.sh”], “builds”: [{ “src”: “src/server.js”, “use”: “@now/node-server” }], “routes”: [{ “src”: “/”, “dest”: “/src/server.js” }]}alias 这里配置上 now.sh 的别名是不会直接生效的,这里只是方便备忘。server.js 是一个需要执行的文件,于是我们将 version 设置为 2,接下来我们就可以在配置中添加 builds 了,对于普通 js 可指定文件使用 @now/node ,这里的 server.js 是开启一个 Node 服务,所以需要使用 @now/node-server。 部署成功以后我们获得了一个 github-trending-graphql-[hash].now.sh 的项目访问地址,如果要访问到项目的实际功能,还需要点开两次两次获得项目功能地址 github-trending-graphql-[hash].now.sh/src/server.js ,如果要直接使用域名直接访问功能,我们这里就需要添加上述配置 route。 每一次部署都会产生一个新的镜像,也会得到一个新的二级域名,如果我们要分享出去无论是自己部署还是用户使用体验都不是很好,我们可以为自己的项目设置一个别名,这里我们为当前项目设置的别名就是 trending.now.sh 。 每次部署的时候我们需要做的工作就是 now && now alias ,now alias 需要指定当前部署获得的项目域名,以及需要设置的别名,$(now) 可以获得部署后获得的域名,于是上述命名就修改成 now alias $(now) trending.now.sh 了,添加 package.json 中,每次部署只需要执行一下 npm run now 。成果展示github trending graphql apionline demo相关项目github trending rest api ...

February 23, 2019 · 3 min · jiezi

json to graphql schema: json2graphql

json2graphqljson2graphql 是一个根据 json 生成 GraphQL Schema 的工具。可在 https://luojilab.github.io/js… 在线体验其功能。关于 GraphQLGraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。由于其强类型,返回结果可定制,自带聚合功能等特性,由 facebook 开源后,被 github 等各大厂广泛使用。核心概念:TypeFieldQuery/MutationArgumentsInputVariablesAliases更多请参考 https://graphql.cn/为什么选用 GraphQL相比 REST API, GraphQL 提供了更高的灵活性。接口调用方能够精确的定义其所需数据,并通知服务方只返回这部分数据,该功能是 REST API 无法提供的。GraphQL 能够使客户端只进行一次接口调用,即可获取多个 REST API 请求返回的数据。这种数据聚合的能力,正是我们所需要的。json protobuf 与 GraphQL由于 protobuf 和 GraphQL 都是强类型的,所以可以直接从 protobuf 的 schema 生成 GraphQL Schema,因而才能有自动聚合 grpc 服务生成 GraphQL 接口的框架 rejoiner。但同样的方法不适用于 json,因为标准的 json 并不包含 schema,单纯根据 json 文件无法确定知道每个字段的类型(因为有空值,以及嵌套的情况)。因而目前无法实现类似 rejoiner for json 这样的全自动框架。我们虽不能生成最终的 GraphQL Schema,但是基于对 json 的解析和一些约定,我们可以生成一个 GraphQL Schema 的草稿,生成 Schema 的绝大部分内容,并将有疑问的地方标记出来。json2graphql 就是一个用 golang 实现的 json 生成 schema 的工具。如果你不熟悉 golang,可以使用其在线版本 https://luojilab.github.io/js…在从 REST API 迁移到 GraphQL 的过程中,我们有很多接口会返回大量字段(几十个),如果完全手动编写这些 Schema,将是非常痛苦的,我们开发 json2graphql 的初衷就是解决这个问题,大大缩短开发时间。以下介绍该工具用法。Usagego run main.go -hNAME: inspect - generate a graphql schema based on jsonUSAGE: main [global options] command [command options] [arguments…]DESCRIPTION: inspect json and generate draft schema.graphqlCOMMANDS: inspect generate a graphql schema based on json help, h Shows a list of commands or help for one commandGLOBAL OPTIONS: –verbose, -v show logs –input value, -i value the json filename –output value, -o value the target filename to store generated schema –help, -h show helpExamplego run main.go -i example.jsonLive Demohttps://luojilab.github.io/js…TODO[x] build it as a web service that render schema on the fly like json.cn[ ] support to read from multi json files.[ ] get input from http request rather than local file.[ ] integrate with graphql server frameworks like gqlgen and auto generate resolver ...

February 2, 2019 · 1 min · jiezi

GraphQL 在 koa 框架中的实践

在之前翻译的一篇文章为什么我们在 API 中使用 GraphQL 中介绍 GraphQL 的作用,之后笔者在 Koa 框架中实现相关接口及调用方式并整理相关实现过程,希望对如笔者一样想要使用 GraphQL 的入门者一些帮助。由于笔者日常工作开发中使用的Node 后台框架是 Koa,因此就以此框架为基础实现 /graphql 接口,接下来会分步介绍实现的步骤与方法。路由配置建立一个路由配置,笔者使用的框架对路由进行封装,只要在指定文件下新建graphql.ts文件夹即可,以下是使用 koa-router 的写法:router.get(’/graphql’, async (ctx, next) => {// do something…})数据定义引入 js 实现 GraphQL 相关模块 graphql,其定义一套数据类型,用于描述我们能从服务查询到的数据,比如 graphql 定义 GraphQLObjectType 、 GraphQLString, GraphQLID, GraphQLList 等相关类型,本次接口需要返回设备基本信息列表,以下是本次接口查询定义的对象import { GraphQLObjectType, GraphQLString, GraphQLID, GraphQLList, GraphQLNonNull } from ‘graphql’;/device.js///id、 baseSn 、 baseWifi 均为数据库中字段let DeviceType = new GraphQLObjectType({ name: ‘Device’, fields: { id: { type: GraphQLID }, baseSn: { type: GraphQLString }, baseWifi: { type: GraphQLString } }})export const devices = { type: new GraphQLList(DeviceType)}实现 GraphQL 查询入口1. 定义查询参数和数据来源前面定义数据的结构和类型,接下来就看一下如何定义数据来源和数据类型:export const devices = { type: new GraphQLList(DeviceType), args: { baseSn: { type: new GraphQLNonNull(GraphQLString) } }, resolve(root, params, options) { return getList({params}).then((data) => { return data[0] }) //the result of th getList function: / * [total, devices] * [1, [ { baseSn, basWifi, id …} ] */ }}在device.js devices 对象中添加 args 属性,定义 baseSn 为查询条件,在 resolve 中调用数据查询函数作为 devices 的返回结果。2. 定义查询入口GraphQL 服务定义大部分都是普通对象类型,但是一个 schema 内定义两个特殊类型:schema { query: Query mutation: Mutation}每个 GraphQL 都会定义一个 query 类型作为查询入口,也会定义 mutation 定义更改操作的接口。// schema.jsimport { GraphQLSchema, GraphQLObjectType } from ‘graphql’;import { devices } from ‘./device.js’export default new GraphQLSchema({ query: new GraphQLObjectType({ name: ‘Query’, fields: { devices // you can define other data here } }) //mutation: …})3.在 Koa 中实现//router.js import { graphqlKoa} from ‘graphql-server-koa’import schema from ‘./schema.js’router.get(’/graphal’, async (ctx, next) => { await graphqlKoa({ schema: schema })(ctx, next) //… })前端接口调用前端使用 jQuery.ajax 进行调用,GraphQL 查询请求与返回的数据结构类似,在查询语句中指定需要查询的字段,比如下列查询中指定 baseSn, baseWifi 两个字段,则会在结果中返回这两个字段而没有 id 字段。$.ajax({ url: ‘/graphql’, data: { query: query { devices (baseSn: "**"){ baseSn, baseWifi } } }/*results"data": { “devices”: [ { “baseSn”: “************”, “baseWifi”: “” } ]} */参考文献[1] GraphQL 官网 [2] https://github.com/graphql/gr… ...

January 27, 2019 · 2 min · jiezi

Github API v4: GraphQL

GraphQL势不可挡,有着即将取代REST的API架构。主要好处就是“你要什么,api就给你什么。而不是你要不要都给你返回一大堆没用的。”而且:GraphQL只需要一个网址URL!https://api.github.com/graphql不像REST,你需要各种各有的URL去申请不同的内容。GraphQL一个URL全够了。而且一般不是很复杂的情况下,你几乎只要request一次这个地址,就能拿到你全部需要的数据了(能按照你的需求返回给你各种嵌套的、格式化的数据)网上看了很多文章解释之后发现还是什么都没懂。所以这篇分享不打算按照常规路线,先用一大堆结构图、语法给你弄懵。这里我想先让它运作起来,有个"Hello world",然后再去深究背后的逻辑和语法。初试GraphQL要说去了解一个API,最好的方式就是用Postman或Insomnia这种REST客户端去连接玩耍了,不需要任何编程,只是手动点一点就ok。”有意思“的是,因为GraphQL太新潮,这两大客户端对它的支持各不相同,使用的参数、格式也大相径庭。下面通过最简单的案例总结一下。Insomnia 访问Github GraphQL 的案例Insomnia对GraphQL的支持相当好,可以说已经领先别人一步。以下为操作步骤:新建request, 设置为POST方式访问https://api.github.com/graphql申请授权认证:Github的API v4不能陌生访问,必须使用自己的账号申请一个token密码串,然后在每次连接API时使用。操作很简单,登录Github后,找到Settings -> Developer settings -> Personal access tokens -> Generate new token,生成一个新的token授权密码串,复制保存到本地备份。添加授权认证:在Insomnia软件里,有两种授权方式都可以达到同样认证效果:明文的Query参数里设置(即在url后面加上参数),或者Header表头里设置。Query里设置的话,格式为:?access_token=xxxxxxxxxxxHeader里设置的话,格式是:名称为Authorization,值为token xxxxxxxxxx。在栏目里面的Body位置选择GraphQL格式:输入Github指定格式的查询语句(看似JSON格式实则不是):query { viewer { login }}点击Send发送请求,如果一切正常,则会得到查询的返回值:Postman访问GraphQL失败不像Insomnia,Postman暂时没有支持GraphQL的选项,但是可以通过类似的操作达到一样的效果。流程是一样的,只是每个地方设置格式都不同,这也是我不断尝试才找到的总结方案(可惜网上相关教程太少)。这里只说不同的地方吧:授权比Insomnia多一种方式,可以在Authorization栏目里面直接选OAuth 2.0然后输入token密码串。最重要的是Body部分,查询语句完全不能使用Github指定的格式。只能选择Body格式为Raw -> JSON(application/json)。然后加上查询语句,格式如下(必须完全符合JSON语法):{ “query”: “query {viewer { login } }"}GitHub GraphQL Explorer这个是Github制作的网页练习机,免去了一切授权等处理,让你只专注于查询语句的调用练习。每次点击运行,都会实时返回对应的数据。如果记不住的、不懂的,还可以点击旁边的Docs,会显示出一个搜索框,显示你需要的内容的文档。GraphQL API Explorer | GitHub Developer Guide常用查询结构下面展示一些我测试过的查询结构,希望能起到帮助作用。为了增强阅读性,节省文字长度,返回值就先不粘上来了。而且返回值几乎就是查询语句的结构,没什么特别新鲜的。查询指定的repo中的issues和comments其中指定了某一个repo(通过owner和name指定),也指定了某一条issue(通过number指定),并要求返回最近的10条comments。

January 26, 2019 · 1 min · jiezi

【译】为什么我们对我们的API中使用GraphQL

本文是对Why we used GraphQL for our API的翻译,如有侵权等其他问题,请联系笔者删除。最近在Mavel我们发布了 Platform API,我们想利用整合的力量,将这个力量直接放入每天使用Marvel的人们的创意社区中,因此我们能更加无缝地工作-与日常服务工具一起工作。什么是一个好的API如果我们曾经写过一个好的API,首先我们需要想想什么是一个好的API。因此我们确定了设计任何API的良好实践,无论是否是在网络上。很棒的文档即使是最改变生活的工具,我不能发现如何去使用,对于自己而言都是无用的。不必要的复杂度不必要的复杂是为了官僚,我们总是更喜欢简单缺乏惊喜因为一些事情用你没有预料的的方式运作,或者因为没有预料到的副作用被抓到是不好玩的。事情应该尽可能的简单明了。我们可以考虑归档出这些点作为开发者体验。这对我们是用意义的–当我们设计app或者web界面,我们会尽量去保持用户体验。API是针对开发者特定的界面,我们也应该做同样的事情。其他的APIs哪里有欠缺没有标准化过去五年大多数的web APIs是REST(ish)和json,而不是稍微有点老的SOAP,RPC,或者自定义的XML。通常,这被视为一件好事,我们看到了APIs的激增,由于设备更加智能和服务已经开始更加紧密的协同工作。问题是虽然json已经变成web APIs之间发送数据的标准,但是每个API由于其独一无二的结构和能力,并且没有标准的方式去描述自身。当每个API和最后一个不同时,无法构建适合所有的工具。因此尽管你们正在使用的API或者一些便利的工具,如:编辑器集成工具或者客户端库,可能很完美的被良好的文档支持。您习惯性地使用的工具可能无法使用您正在使用的API,或者,如果有的话,过于通用,帮助您解决问题独特的部分。事实上,这意味着您没有任何工具。移动网络和设备随着越来越多的网络流量被过渡到移动设备,产生了另个一个问题。移动端设备位于好延迟低带宽的不可靠的网络上。REST API通常要求客户端命中多端去收集呈现视图的多种资源数据(例:在两个单独的调用去获取用户的配置文件和喜欢的菜单)因为移动端网络比其他网络更不可靠,因此当发送多个请求的时候失败的概率更高。这可能使得您获取到部分数据而不能渲染视图,或者渲染占位符当您去重新请求的时候。与此同样糟糕的是,网络延迟是一个大的性能杀手。延迟是两个设备之间传送数据的时间,比如您的手机和Marvel的服务器。当设备和服务器之间的延迟是50ms,意味着数据从设备到服务器间传送需要50ms,RTT(往返时间)是100ms.100ms听起来不算长,但是您必须考虑到发送单个请求不止一次往返。当您接收数据或者发送数据之前,需要进行DNS查询,TLS加密握手以及TCP三次握手,这些都需要一次或者多次往返。我们使用的在网络上传输字节的TCP协议也需要不断的确认收到的数据, 确保丢失的包可以重传。令人悲伤的是,这些确认遵循物理规律,也需要花费往返时间,这给整个网路设置了一个上限,它直接与网络延迟紧密相关。在高延迟的网络中,发送一个包往返时间可能需要1s或者更长的时间。网络延迟极大的超出了app开发者的控制,因此我们需要减少请求来尽可能减少它的影响。另一个对移动端不成比例地对移动端设备影响的问题是过度获取。通常一端返回资源的完整表示,但很有可能客户端不一定需要或者想要所有数据,大多数时候需要的是这些数据的子集。尽管如此,服务器仍旧发送无关的数据,并且客户端对这件事没有发言权。从API端点获取数据的时,很有可能客户端不想要或需要返回的所有数据,但是仍旧需要支付传送和处理的费用,浪费了带宽和CPU周期,造成更长的响应时间,没有任何好处。这些问题的解决方式是什么有一些开源项目试图去解决REST APIs的一些问题,亦即 swagger(OpenAPI)和 API Blueprint。对于swagger 我们已经有了一点内部经验(但是不是特别开心,yaml可能是地狱),并向我们现有的API添加新端的时候试用API BluePrint,但是发现在 MSON中的小的错误很难被追踪(并不比yaml好多少)。尽管这些工具的承诺是很好,他们有一件事情做对了:它们强迫您为API定义一个模式,这个模式好像是系统边界文档一样,系统边界通常是最能感受到集成痛苦的地方。一旦你获取到一个模式,你能用它做各种各样酷炫的东西:生成文档页面,启动模拟服务器进行开发,如果你有倾向,甚至能生成客户端API代码。因为模式是被标准方式具体化的,因此API构建工具是很容易在使用相同标准的API之间进行移植,因为一切都是提前定义的,你的API消费者确切地知道他们的期望是什么以及对您的期望是什么。这也正是GraphQL做正确的事情,GraphQL定义包含客户端可用所有数据类型、更改和查询的模式。这样每个人都知道他们的立场。我能立刻确切地明白我能获取那种操作,它们接受那种类型作为输入,返回那种类型作为输出。尽管 swagger和API Blueprint在请求和响应体中携带一个模式,但是它们不能处理过度获取和发送多个请求的问题。如果您将在您的API中解决这些问题,那么它将是自定义的、非标准的、是单个API独有的。通常,您最终会为特定端点编写视图。对于前面提到的例子,这意味着有一端会立刻返回用户和菜单数据。那只是单个视图,在您的应用中有多少个独特的视图?这可能会变得混乱。那么为什么是GraphQL不想REST,GraphQL的核心思想与解决这些问题紧密相关。每次调用仅仅返回在这次请求特定的数据,这有一些好处。首先,完全通过放在客户端手中,解决了过度请求的问题。第二,它通过需要客户端立刻请求它们所需要的数据移除了多次请求的需求。这种方式的第三个优点是,它允许我们作为API的操作者去确切的查看谁正在请求每个字段的人,这使得我们随着时间的流逝更容易弃用有一些字段,让新的集成商不去使用,并且返回所有存在的集成的列表,并且与他们取得联系提供升级路径。正如我前面提到的,工具也是我们考虑的一个因素,所有上述被提及的解决方案有一些相同的工具和相对健康的社区,但是GraphQL超越了其他两个。Gra主要被非常大很活跃的react社区。这意味着大量优秀的工具使得开发者的体验尽可能的好。比如,连接您的编辑器到模式,对您的查询划线,在您有机会之前它们之前对错误进行标注,将其与自动完成功能相集成,当您输入的时候,能为您提供一些建议。我喜欢的工具之一的是GraphiQL,这是一个为浏览器中运行的GraphQL APIs 构建的IDE。正如下图您看到的,GraphiQL给您提供编地方去写查询(具有您期待的功能:语法高亮,自动补全),查看结果和参考文档。它基于浏览器意味着我们能够把它放在任何公共的地方(如Mavel所做的那样)并且允许某人立刻在友好的开发环境中获取我们的API。事实证明是一个有效的方式去控制GraphQL本身以及API的细节,真正地帮助人们开始去运行。除了它带来的其他好处之外,这也是我们选择使用GraphQL的原因,它简单的运行我们提供比其它替代方案更好的开发者体验。

January 20, 2019 · 1 min · jiezi

GraphQL 的初学者指南

今天最常讨论的术语之一是 API,很多人不知道 API 到底是什么,API 是 Application Programming Interface(应用程序编程接口)。顾名思义,它是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。你可以将 API 想象成一个酒保。你向酒保要一杯酒,他们会给你想要的。简单,但的 API 有什么问题的呢?自从现代 Web 出现以来,构建 Api 并不像听起来那么困难,但是学习和理解 Api 才是比较难。开发人员是大多数据使用你的 API 来构建某些内容或仅使用数据。所以你的 API 应该尽可能的简洁和直观, 好的 API 是非常容易使用和学习的。直观,在开始设计 API 时常要记住的一点。我们已经使用 REST 构建 Api很长时间了。随之而来的也有一些问题,在使用 REST 设计构建 API 时,你会遇到以下问题:涉及很多端于开发人员来说,学习和理解你的 API 要困难得多* 信息的获取有多有少为了解决这些问题,Facebook创建了 GraphQL。现在,作者认为 GraphQL 是构建 Api 的最佳方式。这篇文章将告诉你为什么要学习了解一下 GraphQL。什么是 GraphQLGraphQL是 Facebook 开发的一种开源查询语言。它为我们提供了一种更有效的设计、创建和使用 Api的方法。从根本上说,它是 REST 的替代品。GraphQL有很多特性,比如:GraphQL查询总是能准确获得你想要的数据,不多不少,所以返回的结果是可预测的, 不再像你使用 REST 那样过度获取信息。它为我们提供了同一个端,对于同一个 API,没有版本2或版本3。给 GraphQL API 添加字段和类型而无需影响现有查询,老旧字段可以废弃,从工具中隐藏。GraphQL是强类型的,通过它,可以在执行之前验证 GraphQL 类型系统中的查询, 它帮助我们构建更强大的 Api。这是对 GraphQL 的基本介绍——为什么它这么强大,为什么它现在这么流行。如果你想了解更多关于它的信息,可以访问 GraphQL网站 学习。开始本文的主要目的不是学习如何设置 GraphQL服务器,所以我们现在还没有深入研究。 文本的目标是了解 GraphQL 在实践中的工作原理,因此这里使用简约的零配置 GraphQL 服务器的 Graphpack。 开始项目前,首先我们创建一个新文件名为 graphql-server, 在 mac 终端执行mkdir graphql-server接着进入该文件,执行npm init -y或者执行yarn initnpm 将创建一个包 package.json 文件,这个包是你安装的所有依赖项和命令。现在,我们要安装唯一的依赖项。Graphpack 允许创建零配置的 GraphQL 服务器。由于刚刚开始使用 GraphQL,这将帮助我们继续学习GraphQL 更多的内容,而不必担心服务器配置,执行以下命令:npm install –save-dev graphpack或者使用 yarn 安装:yarn add –dev graphpack安装 Graphpack 之后,转到 package.json文件中的脚本,并在其中输入以下代码:“scripts”: { “dev”: “graphpack”, “build”: “graphpack build”}接着创建一个名为 src 的文件夹,它将是整个服务器中唯一的文件夹。在 src 文件夹中创建一个名为 schema.graphql 的文件,并写入以下代码:type Query { hello: String}在 schema.graphql 文件将是我们的整个 GraphQL的模式(Schema)。接着在 src 下创建文件 resolvers.js,并写入以下代码:import { users } from “./db”;const resolvers = { Query: { hello: () => “Hello World!” }};export default resolvers;这个 resolvers.js 文件是我们提供 GraphQL 操作转换为数据的指令的方式。接着在 src 下创建一个 db.js 文件并写入以下代码:export let users = [ { id: 1, name: “John Doe”, email: “john@gmail.com”, age: 22 }, { id: 2, name: “Jane Doe”, email: “jane@gmail.com”, age: 23 }];在本教程中,不使用真实的数据库,所以这个 db.js 文件将模拟一个数据库,只是为了学习的目的。现在 src 的结构如下:src |–db.js |–resolvers.js |–schema.graphql接着运行 npm run dev 或者 yarn dev 启动服务在浏览器打开 localhost:4000。这里就实现我们在 GraphQL 中的第一个查询,更改和订阅,打开界面如下:你可以看到 GraphQL Playground,这是一个功能强大的 GraphQL IDE,可用于更好的开发工作流程。 如果你想了解有关 GraphQL Playground的更多信息,请单击此处。模式(Schema)GraphQL有自己的语言类型,用于编写模式。 这是一种人类可读的模式语法,称为 规范与描述语言(SDL)。无论使用何种技术,SDL 都是相同的 - 你可以将其用于您想要的任何语言或框架。这种模式语言非常有用,因为它更直观的看出 API 具有哪些类型,一看到 API 就知道怎么使用。类型(Type)类型是 GraphQL 最重要的特性之一。类型是表示 API 外观的自定义对象。例如,如果你正在构建一个社交媒体应用程序,那么你的 API 应该具有诸如文章、用户、赞、组等类型。类型具有字段,这些字段返回特定类型的数据。 例如,我们要创建一个 User 类型,我们应该有一些 name,email 和 age 字段。 类型字段可以是任何类型,并始终返回一种数据类型,如 Int,Float,String,Boolean,ID,对象类型列表或自定义对象类型。现在编写的第一个 Type,在 schema.graphql 文件中用以下内容替换已存在的 Query 类型:type User { id: ID! name: String! email: String! age: Int}每个用户都将拥有一个 ID,因此为其提供了 ID 类型。 用户也会有一个 name 和 email,所以给它一个字符串类型和一个 Int 类型。但是,在每一行的结尾的 !呢? 感叹号表示字段不可为空,这意味着每个字段必须在每个查询中返回一些数据。 User 中唯一可以为空的字段是 age。在GraphQL中,有三个主要概念:query (查询) — 从服务器获取数据的方式。mutation (更改) — 修改服务器上的数据并获取更新数据的方法(创建、更新、删除)。subscription (订阅) — 当希望数据更改时,可以进行消息推送,使用 subscription 类型(针对当前的日趋流行的 real-time 应用提出的)。query (查询)为了简单地解释这一点,GraphQL中的查询是获取数据的方式。关于 GraphQL 中的查询,最吸引的地方之一就是你将获得所需的确切数据,不多不少。这对我们的 API 产生了巨大的积极影响——不再像 REST API 那样获取过多或不足的信息。我们将在 GraphQL 中创建第一个类型的 Query。 我们所有的查询都将以此类型结束。 首先,在文件 schema.graphql 编写一个名为Query 的新类型:type Query { users: [User!]!}这很简单:用户查询将返回给我们一个或多个用户的数组。 它不会返回 null,因为我们放入了 ! ,这意味着它是一个不可为空的查询, 它总会返回一些数据。但我们也可以返回特定用户。 为此,创建一个名为 user 的新查询。 在我们的 Query 类型中,写以下代码:user(id: ID!): User!现在 Query 类型应该是这样的:type Query { users: [User!]! user(id: ID!): User!}如上所见,使用 GraphQL 中的查询,还可以传递参数。在本例中,要查询特定用户,所以要传递其用户的 ID。但是,你可能想知道: GraphQL 如何知道从哪里获取数据? 这就是为什么我们应该有一个 resolvers.js 文件。该文件告诉 GraphQL 它将如何以及在何处获取数据。首先,看看我们的 resolvers.js 文件并里该文件里导入 db.js 文件。我们刚才创建的 resolvers.js 文件内容如下:import { users } from “./db”;const resolvers = { Query: { hello: () => “Hello World!” }};export default resolvers;现在,我们将创建第一个 Query,在 resolvers.js 文件并替换 hello 函数。 现在 resolvers.js 内容如下 :import { users } from “./db”;const resolvers = { Query: { user: (parent, { id }, context, info) => { return users.find(user => user.id == id); }, users: (parent, args, context, info) => { return users; } }};export default resolvers;现在,解释它是如何工作的:每个查询解析器都有四个参数。 在 user 函数中,我们将 id 作为参数传递,然后返回与传递的 id 匹配的特定 user,这很简单。在 users 函数中,我们只是返回已存在的 users 数组,这个数组存放的是所有的用户。现在,我们将测试查询是否工作正常,转到 localhost:4000,输入以下代码:query { users { id name email age }}它应该返回给你我们所有的用户。如果想返回特定的用户:query { user(id: 1) { id name email age }}mutation (更改)在 GraphQL 中,更改是修改服务器上的数据并获取更新数据的方式, 你可以像 REST 的CUD(创建,更新,删除)一样思考。在 GraphQL 中创建我们的第一个类型修改,这里所有的修改都将在这个类型中结束。 首先,在 schema.graphql文件中编写一个名为mutation 的新类型:type Mutation { createUser(id: ID!, name: String!, email: String!, age: Int): User! updateUser(id: ID!, name: String, email: String, age: Int): User! deleteUser(id: ID!): User!}这里主要定义三个修改数据的方法:createUser:传入需要创建用户的 ID,name,email 和 age,它会返回一个新用户给我们。updateUser:传入需要修改用户的 ID,name,email 和 age(非必传),它会返回一个新用户给我们。deleteUser: 传入需要删除用户的 ID,它会返回一个新用户给我们。现在,在 resolvers.js 文件并在 Query 对象下面,创建一个新的 mutation 对象,如下所示:Mutation: { createUser: (parent, { id, name, email, age }, context, info) => { const newUser = { id, name, email, age }; users.push(newUser); return newUser; }, updateUser: (parent, { id, name, email, age }, context, info) => { let newUser = users.find(user => user.id === id); newUser.name = name; newUser.email = email; newUser.age = age; return newUser; }, deleteUser: (parent, { id }, context, info) => { const userIndex = users.findIndex(user => user.id === id); if (userIndex === -1) throw new Error(“User not found.”); const deletedUsers = users.splice(userIndex, 1); return deletedUsers[0]; } }现在 resolvers.js 文件内容如下:import { users } from “./db”;const resolvers = { Query: { user: (parent, { id }, context, info) => { return users.find(user => user.id == id); }, users: (parent, args, context, info) => { return users; } }, Mutation: { createUser: (parent, { id, name, email, age }, context, info) => { const newUser = { id, name, email, age }; users.push(newUser); return newUser; }, updateUser: (parent, { id, name, email, age }, context, info) => { let newUser = users.find(user => user.id === id); newUser.name = name; newUser.email = email; newUser.age = age; return newUser; }, deleteUser: (parent, { id }, context, info) => { const userIndex = users.findIndex(user => user.id === id); if (userIndex === -1) throw new Error(“User not found.”); const deletedUsers = users.splice(userIndex, 1); return deletedUsers[0]; } }};export default resolvers;现在,我们要测试我们的 mutations 是否正常。转到localhost:4000,输入以下代码:mutation { createUser(id: 3, name: “Robert”, email: “robert@gmail.com”, age: 21) { id name email age }}subscription (订阅)如我之前所说,订阅是你与服务器保持实时连接的方式。这意味着无论何时在服务器中发生事件,并且每当调用该事件时,服务器都会将相应的数据发送到客户端。通过订阅,你可以让你的应用在不同的用户之间保持更新。基本订阅是这样的:(sample.graphql )subscription { users { id name email age }}你会说它非常类似于查询,是的, 但它的工作方式不同。当服务器中发生更新时,服务器将运行订阅中指定的 GraphQL 查询,并向客户机发送一个新更新的结果。在这篇文章中,我们不打算讨论订阅,但是如果你想阅读更多关于订阅的信息,请单击这里。总结如你所见,GraphQL 是一项非常强大的新技术。 它为我们提供了构建更好和精心设计的API的真正能力。 这就是为什么作者建议你现在开始学习它,从本文本作者的角度来说,它最终将取代 REST。原文:https://medium.freecodecamp.o…你的点赞是我持续分享好东西的动力,欢迎点赞!一个笨笨的码农,我的世界只能终身学习!更多内容请关注公众号《大迁世界》! ...

January 11, 2019 · 4 min · jiezi

GraphQL 入门详解

简介定义一种用于API调用的数据查询语言核心思想传统的api调用一般获取到的是后端组装好的一个完整对象,该对象的结构相对固定,而且前端可能只需要用其中的某些字段,大部分数据的查询和传输工作都浪费了。graphQL提供一种全新数据查询方式,可以只获取需要的数据,使api调用更灵活、高效和低成本。特点需要什么就获取什么数据支持关系数据的查询API无需定义各种路由,完全数据驱动无需管理API版本,一个版本持续演进支持大部分主流开发语言和平台强大的配套开发工具使用方法下面我们通过搭建一个SpaceX的新闻网站来直观学习graphQL的基本使用方法,所有数据由 官方API 获得。服务端服务端采用node + express。新建一个node项目,安装如下依赖:$ npm i graphql express-graphql express axios创建入口文件 server.js,里面创建express服务。使用graphQL我们只需要设置一个路由,所有的请求都由这个graphQL的request handler处理:const express = require(’express’);const graphqlHTTP = require(’express-graphql’);const schema = require(’./schema’);const app = express();app.use(’/graphql’, graphqlHTTP({ schema, graphiql: true}));const PORT = process.env.PORT || 5000;app.listen(PORT,()=>console.log(Server started on port ${PORT}));graphqlHTTP是grapql的http服务,用于处理graphql的查询请求,它接收一个options参数,其中schema是一个 GraphQLSchema实例,我们待会儿定义。graphiql设置为true可以在浏览器中使用GraphiQL直接进行调试,之后会看到。更多express-graphql的用法请参考 Github express-graphql。schema接着我们定义schema,schema意为‘模式’,其中定义了数据模型的结构、字段的类型、模型间的关系,是graphQL的核心。新建schema.js文件,定义两个数据模型:LaunchType(发射)和 RocketType(火箭)。注意字段的数据类型需要使用GraphQL定义的,不能使用js中的基本数据类型。const { GraphQLObjectType, GraphQLInt, GraphQLString, GraphQLBoolean, GraphQLList, GraphQLSchema } = require(‘graphql’);const LaunchType = new GraphQLObjectType({ name: ‘Launch’, fields: () => ({ flight_number: { type: GraphQLInt }, mission_name: { type: GraphQLString }, launch_date_local: { type: GraphQLString }, launch_success: { type: GraphQLBoolean }, rocket: { type: RocketType }, })});const LaunchType = new GraphQLObjectType({ name: ‘Rocket’, fields: () => ({ rocket_id: { type: GraphQLString }, rocket_name: { type: GraphQLString }, rocket_type: { type: GraphQLString } })});有了数据模型之后,我们需要从数据库或者第三方API获取数据,在此我们从spacex的官方API获取。我们需要定义一个root query,root query将做为所有查询的入口,处理并返回数据,更多请参考 GraphQL Root fields & resolvers。在 schema.js中增加代码:const axios = require(‘axios’);…const RootQuery = new GraphQLObjectType({ name: ‘RootQueryType’, fields: { launches: { type: new GraphQLList(LaunchType), resolve(parent, args) { return axios.get(‘https://api.spacexdata.com/v3/launches').then(res => res.data); } } }});module.exports = new GraphQLSchema({ query: RootQuery});查询列表完成这一步,api服务基本搭建完成!我们看一下效果,在浏览器中输入 http://localhost:5000/graphql 将打开 Graphiql(生产环境建议禁用):我们可以只查询所有的 flight_number:或者更多的属性:是不是很简单很神奇!单个查询我们也可以通过传入参数查询单条信息:const RootQuery = new GraphQLObjectType({ name: ‘RootQueryType’, fields: { … launch: { type: LaunchType, args: { flight_number: { type: GraphQLInt } }, resolve(parent, args) { return axios.get(https://api.spacexdata.com/v3/launches/${args.flight_number}) .then(res => res.data); } } }});结果:前端刚刚我们都是用GraphiQL在浏览器调用接口,接下来我们看一下在前端页面中怎么调用graphql服务。前端我们使用react。在项目根目录初始化react项目:$ npx create-react-app client为了便于调试,在package.json中增加scripts:“start”: “node server.js”,“server”: “nodemon server.js”,“client”: “npm start –prefix client”,“dev”:“concurrently "npm run server" "npm run client" “样式我们使用bootswatch中的一款主题:GraphQL的客户端有多种实现,本次项目使用 Apollo,最流行的GraphQL Client。更多client请参考 GraphQL Clients。安装依赖安装如下依赖:$ cd client$ npm i apollo-boost react-apollo graphql其中 apollo-boost 是apollo client本身,react-apollo 是react视图层的集成,graphql 用于解析graphql的查询语句。设置client修改App.js内容如下:import React, { Component } from ‘react’;import ApolloClient from ‘apollo-boost’;import { ApolloProvider } from ‘react-apollo’;import ‘./theme.css’;import ‘./App.css’;import logo from ‘./spacex-logo-light.png’const client = new ApolloClient({ uri: ‘http://localhost:5000/graphql’});class App extends Component { render() { return ( <ApolloProvider client={client}> <div className=“container”> <img src={logo} id=“logo” /> </div> </ApolloProvider> ); }}export default App;和redux使用<Provider>传递store类似,react-apollo 通过 <ApolloProvider>将apollo client向下传递。实现query接着我们来实现显示launches的component,新增文件 components/Launches.js:import React, { Component, Fragment } from ‘react’;import gql from ‘graphql-tag’;import { Query } from ‘react-apollo’;import LaunchItem from ‘./LaunchItem’;const LAUNCHES_QUERY = gql query LaunchesQuery { launches { flight_number, mission_name, launch_date_local,, launch_success, } };export class Launches extends Component { render() { return ( <Fragment> <h1 className=“display-4 my-3”>Launches</h1> <Query query={LAUNCHES_QUERY}> { ({ loading, error, data }) => { if (loading) return <h4>Loading…</h4> if (error) console.log(error); return ( <Fragment> { data.launches.map(launch => <LaunchItem key={launch.flight_number} launch={launch}/>) } </Fragment> ) } } </Query> </Fragment> ) }}export default Launchesquery语句通过 graphql-tag 定义,传入 <Query> 执行获取数据并传入 LaunchItem 显示。components/LaunchItem.js:import React from ‘react’export default function LaunchItem({ launch: { flight_number, mission_name, launch_date_local, launch_success } }) { return ( <div className=“card card-body mb-3”> <div className=“col-md-9”> <h4>Mission: {mission_name}</h4> <p>Date: {launch_date_local,}</p> </div> <div className=“col-md-3”> <button className=“btn btn-secondary”>Launch Details</button> </div> </div> )}运行由于本地调试,client和server分别运行在不同的端口,所以需要先进行跨域处理,使用 cors。server.jsconst cors = require(‘cors’);…app.use(cors());效果好了,大功告成,我们来看一下效果:结语今天就主要介绍GraphQL工程的搭建和GraphQL Query的使用,更多关于GraphQL的内容比如 Mudtation下次有空会跟大家逐步讲解。本文灵感来源:Youtube@Traversy Media,感谢本文完整demo(增加部分功能):Github@MudOnTire ...

January 4, 2019 · 2 min · jiezi

2019年前端的3个趋势

简介:JavaScript 应用范围广泛,静态类型语言 TypeScript 会继续得到更多开发者的青睐。组件成为前端最基本的物料,CSS 融合在组件中(CSS in JS)的方案日趋成熟。前端的“端”越来越多, API 查询语言 GraphQL 会继续保持高速增长 。JavaScript 应用范围广泛,TypeScript 更受青睐在 github 2018 调查报告的中,JavaScript 连续多年稳居第一,成为最受欢迎的开发语言。从 Stack Overflow 的调查报告中,我们可以看到更详细的数据,任意两个开发者中至少有一个会 JavaScript,并且这个比例还在持续增长,从 2016年的 55.4%,到 2017年的 62.2% ,到 2018 年的 69.8%。在 npm 的调查报告中,JavaScript 生态圈也是非常繁荣,module 的数量继续保持高速增长,将其他语言远远的甩在了后面。图一: npm 2018 调研报告 - Module Counts从使用范围上看,JavaScript 可以写前端、服务端、移动端,甚至还可以写物联网应用。在 npm 2018 的调研报告中,大多数 JavaScript 开发者写 web 前端应用(93%)和 node.js 服务端应用(70%)。在 stateofjs 2018 的调研报告中,还有相当数量的 JavaScript 开发者写移动或桌面应用,例如 Electron(19.6%)、React Native(18.7%)、Native Apps(10.6%), Flutter 、Weex、PWA 都在 1% 以内。备注:npm 和 stateofjs 的调研用户群体特征类似,统一归类为 JavaScript 开发者。图二: npm 2018 调研报告 - The JavaScript I write runs on…值得注意的是,TypeScript 在 2018 年得到更多开发者的青睐。在 github 语言排行版中,TypeScript 上升了 3 名,排到了第 7 的位置。在 stateofjs 2018 的调研报告中, JavaScript 开发者有 86.3% 愿意继续使用 ES6,有 46.7% 愿意继续使用 TypeScript。排在第三、四的是 Facebook 的 Flow 和 Reason 语言,但是占比都不高。图三:stateofjs 2018 调研报告- JavaScript Flavors从互联网的发展历史的角度看,2010 年 3G (国内)开始普及,2014 年 4G 全面铺开,拉开移动互联网的序幕。互联网从传统的内容提供者,转变成了服务提供者。前端应用也发生的本质的转变,从传统互联网时代的内容展示,转变成了拥有复杂交互的逻辑的服务提供窗口。随着前端应用变得越来越复杂,和 JavaScript 应用的领域越来越广泛,传统 JavaScript(ES5) 已经适应复杂的开发需求,因此功能更加强大的 ES6 孕育而出。在 JavaScript 应用复杂度不断增加的背景下,预计 2019 年,静态类型语言 TypeScript 会继续得到更多开发者的青睐。TypeScript 属于 ES6 的超集,一方面它可以很好的兼容 ES6 语法,另一方面它又提供了可选的静态类型检查和接口(interface)的功能。在开发复杂度高、需要大规模合作的 JavaScript 应用时,TypeScript 相对 ES6 不妨是一种更好的选择。组件成为最基本的前端物料,CSS in JS 让组件化更彻底在 stateofjs 2018 的调研报告中, JavaScript 开发者有 64.8% 愿意继续 React,有 28.8% 愿意继续 Vue。但根据个人观察,在国内 Vue 开发者会比 React 多一些,这可能是因为 Vue 上手简单并且有完善的中文文档。Angular 方面,有超过一半使用 Angular 框架的开发者表示,不愿意继续使用 Angular 进行开发了。而其他开发框架 Preact、Ember、Polymer、JQuery 的使用量都很少。现在,React 和 Vue 已经成为前端开发框架的双雄,不会 React 或 Vue 可能连工作都不好找。图四:stateofjs 2018 调研报告 - Front-end Frameworks组件是 React 和 Vue 最强大的功能之一。在 Vue 中一个 .vue 文件就是一个组件,包含 Template、JS、CSS 三个部分,其中 CSS 部分是可选的,开发者也可以将 CSS 独立出去。在 React 中一个 .jsx 文件就是一个组件,但是 JSX 只能包含 Template、JS 两个部分,组件的 CSS 部分必须 import from ‘xxx.css’ 进来。无论是 React 还是 Vue,都改变不了 CSS 全局作用域的问题。开发者可以在一个组件中,通过 Selector,如 .class .id ,取到本该属于其他组件的 CSS 样式。组件本应是一个独立的作用域,但是它的 CSS 竟然是全局的!在应用复杂度低、单人开发的情况下 CSS 全局作用域不算大问题。但是在多人合作开发的场景下,可能会因此导致样式冲突。比如,因为引入了 B 开发者的组件,A 开发者的组件样式错乱了,这就导致了较高的联调成本。图五:CSS document level V.S. component level解决的思路就是,使用 CSS in JS 的工具,使得 CSS 只对它归属的组件生效。CSS in JS 的方案有很多,主流的有:styled-components、emotion、css-modules、aphrodite、glamor、glamorous、radium、react-jss。styled-components 方案使用人数最多,emotion 方案排第二并且增长势头凶猛,而 css-modules 方案在两年前已经停止维护了,不再推荐。styled-components 的写法太反直觉,个人更喜欢 emotion。从下载量的增长势头来看 emotion 比 styled-components 更快。因此,如果有 CSS in JS 需求的项目,更加推荐 emotion。相信在 2019 年,CSS in JS 方案会更加成熟,我们不妨期待吧。图六: npmtrends.com CSS in JS 方案下载量对比“端”越来越多,GraphQL 继续保持高速增长在移动互联网时代来临之前,传统意义上的前端只有浏览器的 PC 端。移动互联网兴起后,出现了浏览器的 H5 端、iOS 端、Android 端。再后来一些平台级 App ,比如微信、QQ,推出了自己的 JS-SDK,Hybird 也成为了新的端。近两年,微信、支付宝、百度、头条也推出了自己的小程序平台,小程序也成为了新的端。每个端都有自个儿的个性,不存在一种大统一的方案,可以适配所有的端。这导致了同一个业务,需要在 6 个端,开发 6 次、联调 6 次。我们假设有一个这样的 API,它包含了该业务在各个端上所有的数据,这不就解决了多次联调的问题了嘛。虽然还是需要开发 6 次,但是现在因为只有 1 个 API,所以联调次数变成了 1 次。但是该方案的背后的代价是,加载慢、维护成本高。任意 1 个端,都要获取其他 5 个端的上差异化的数据,加载能不慢嘛。如果 API 有改动,可能会影响到 6 个端的代码,维护起来也费劲。稍作改变,现在我们假设,前端可以通过一种标准的 API 查询语法,精确地获取任意自定义的数据,在服务端通过解析前端查询语句,返回其自定义的查询数据。虽然还是 6 个端,1 个 API,但是每个端可以只获取自己的数据,不就解决了加载慢的问题了嘛。如果某个端需要增改获取的数据,只需要修改这个端的查询语句即可,这不就解决了维护成本高的问题了吗。通过定义一种标准的 API 查询语法,可以使得前端获取 API 数据,就像从数据库获取数据一样方便和灵活。GraphQL 就定义一套标准的 API 查询语法,在保持灵活性和可维护性的前提下,极大的降低了联调成本。备注:GraphQL 官方使用的例子是,一个业务要请求多个 REST 规范的 API 。但是,国内通常使用的不是准守标准的 REST API ,他们的痛点在国内不那么痛,所以改用多端多 API 联调成本高来举例。图七:@helferjs 从REST到GraphQL因为使用 API 查询语言 GraphQL 获取的方法太简单了,所以连数据管理的事省了。也就是说,使用 GraphQL 可以把 Redux、Mobx 干的活给省了。我们可以看到,在 stateofjs 2018 调研报告中, 把 GraphQL 和 Redux、Mobx 都归类为一类 —— 数据层(Data Layer)。报告中指出,有 47.2% 的 JavaScript 开发者表示会继续使用 Redux,20.4% 会继续使用 GraphQL, 5.6% 会继续使用 Mobx。需要留意的是,有 62.5% 表示对 GraphQL 感兴趣,因此 GraphQL 获得 stateofjs 的最感兴趣奖(Highest Interest)。图八:stateofjs 2018 调研报告 - Data Layer预计 2019 年,GraphQL 会继续保持高速增长,被更多的开发者使用。在 npm 2018 调研报告中,特意指出了 GraphQL 的客户端库 Apollo 的下载量保持着高速的增长。图九:npm 2018 调研报告-GraphQL continues hyper-growth ...

January 4, 2019 · 2 min · jiezi

GraphQL —— 标量类型

标量(ScalarTypeDefinition)是 GraphQL 中不可分割的原子数据类型,在服务中充当叶子节点。对于客户端而言,合法的查询集(Select Set)必须到达叶子节点,也就是到达标量类型节点。GraphQL 规范提供了五种标量:Int: 32 位有符号整型,超出精度范围后,引擎会抛出异常Float: 有符号双精度浮点数,超出精度范围后,引擎会抛出异常String: 字符串,用于表示 UTF-8 字符序列Boolean: bool 值ID: 资源唯一标志符1. ID 特性上述五种类型与其他语言对应的类型定义相似,相信读者老爷们都已经非常熟悉,无需赘述,唯一值得探讨的是 ID 类型。表现上 ID 类型只是一个字符串格式的值,引擎支持字符串解析值,也支持将 Int 解析值转换为字符串类型;语义上"ID" 类型应该用于唯一标志一个资源对象,也就是说,使用相同 ID 值,无论查询多少次,结果都应该是同一对象,这一点有助于实现缓存,是 GraphQL 推荐的缓存方案;引擎并不限制解析值的唯一性,查询结果包含多个 ID 值相同的节点是合法的。我们来看一下例子加深印象:[ // 字符串类型 {id: ‘1’}, // int 类型,引擎会将其转换为字符串 {id: 1}, // float 类型 // 非法值,引擎不支持float转换 // 将抛出 TypeError 错误 {id: 1.2}, // 与上面第一条重复 // 合法值,引擎并不强制 ID 值的唯一性 {id: ‘1’}]2. 自定义标量类型除规范定义的标量外,还可以按需定义业务范畴内的标量。语法非常简单:scalar Datetime注意,这只是语义范畴定义,还需要定义序列化、反序列化函数:new GraphQLScalarType({ name: “Datetime”, description: “日期时间标量类型”, // 序列化函数 serialize(value) { return value.toString(); }, // 解析函数 parseValue(value) { if (typeof value === “string”) { return new Date(value); } throw new Error(“参数类型错误”); }, // 解析函数 parseLiteral(ast) { if (ast.kind === Kind.STRING) { return new Date(ast.value); } throw new Error(“参数类型错误”); }});下面我们一个一个看这些配置:name: 字段名,请保持与 schema 中定的标量类型名称保持一致description: 类型描述,在一些诊断工具上还是很有用的serialize: 序列化函数,用于将结果转换为适合 http 传输的数值类型parseValue: 解析函数,用于将客户端通过 variables 参数传递的数值为 Date 类型parseLiteral: 同样是解析函数,将客户端传递的 字面量参数 解析为 Date 类型配置中的 parseValue、parseLiteral 两个函数功能上相似,都用于解析客户端参数,分别处理两种参数传递方式:# variables 参数# 引擎将调用 parseValue 函数query (before: Datetime){ users(before: $before) { id name }}variables { before: “1991-02-19”}# 字面量参数# 引擎将调用 parseLiteral 函数query { users(before: “1991-02-19”) { id name }}最后说一些注意的点:如果类型确定不会作为 InputType,可以省略 parseValue、parseLiteral。parseValue 接收到的是 variables 对象中对应的值;而 parseLiteral 接收的则是引擎从 query 语句中解析出的 AST 节点。AST 节点内容形如:{ // 字面量类型 “kind”: “StringValue”, // 字面量值 “value”: “1991-02-19”, // 指明字面量是否为 BlockStringValue 类型 “block”: false, // token 位置 “loc”: { “start”: 18, “end”: 30 }}3. 返回对象的标量标量类型也支持返回结构化的对象,只要能为引擎提供符合规则的 serialize 函数,一切皆有可能。我们可以写出这样一个标量:// Address 对象类型,不过这是一个标量new GraphQLScalarType({ name: “Address”, description: “对象类型的标量”, serialize(value) { // value 为对象类型 // value = { city: ‘深圳’, province: ‘广东省’, country: ‘中国’ } return value; }});但是要注意,标量类型是 不可分割 的,不能再传入查询子集:# 合法请求query { users { id name # Address 类型值 bornOrigin }}返回结果:{ “data”: { “users”: [ { “id”: “1”, “name”: “foo”, “bornOrigin”: { “city”: “深圳”, “province”: “广东省”, “country”: “中国” } } ] }}完整代码在 此处。能做是一回事,该不该这么做,又是另一回事,返回对象的标量虽然合乎规则,但却违反了 按需加载 这一重要原则,没有实际意义也不值得推崇。总结标量是 GraphQL 中的原子类型,一般充当查询的叶子节点。GraphQL 规范提供了五种标量类型,其中 ID 最为特殊,用于唯一标志一个资源实例。在标准标量之外,也可以按需定义新的标量,规则如上。 ...

December 20, 2018 · 2 min · jiezi

GraphQL —— 接口类型

在 GraphQL 中,接口(InterfaceTypeDefinition)也是一种命名字段集合,定义规则与对象类型极其相似,同样支持 字段名、类型、参数 三要素。与 OOP 概念类似,GraphQL 中的接口只是对资源的抽象描述,必须被其他对象类型实现,才能正常使用。我们来看个例子:interface NamedEntity { name: String}type User implements NamedEntity { id: ID! name: String}上例中,NamedEntity 即为接口;User 是实现了该接口的对象类型。注意,实现类必须实现接口的所有字段,字段名、类型、参数都必须与接口匹配。GraphQL 支持多继承:interface NamedEntity { name: String}interface Node { id: ID!}‘‘‘非法示例:没有实现Node接口的id字段’‘’type User implements NamedEntity & Node { name: String}那么,在什么场景下应该使用接口?我们要理解,接口是对资源的抽象描述,不一定完备、详尽,但往往能表述多类相似资源的共同特征,所以如果服务中存在一些具备共性的类型,而用户需要关注共同的这一部分,就应该使用接口。比如,我们有三种类型的商品:饮料、图书、电器:type Drinks { id: ID! name: String! price: Float! ’’’ 容量,单位为ml ’’’ capacity: Float!}type Book { id: ID! name: String! price: Float! ’’’ 作者 ’’’ author: [People] issn: String!}type ElectricalEquipment { id: ID! name: String! price: Float! ’’’ 生产商 ’’’ manufacturer: Company}上面三个商品对象有三个相似的属性:id、name、price,是商品资源的不同类型。现在,我们需要实现根据名称搜索商品,如果接口功能,就必须使用近似的逻辑,在三种类型节点上,重复定义三次;如果未来我们增加更多公共查询逻辑,我们又得把逻辑重复三遍,这显然不是一个好的设计。这种情况下就适合使用接口,将三个公共字段抽取出来,再以接口类型对外暴露商品的聚合查询节点:interface Item { id: ID! name: String! price: Float!}type Drinks implements Item{ … }type Book implements Item{ … }type ElectricalEquipment implements Item{ … }type Query { ’’’ 商品列表,支持按商品名查询 ’’’ items(name: Sring): [Item]}而对于客户端来说,针对接口节点的查询,除了接口的属性外,也支持查询实现类的字段:query { items(name: ‘coka’) { name … on Drinks { capacity } }}代码片段 … on Drinks { capacity },被称为 Inline Fragments。针对这段查询,引擎会帮助判断如果解析结果为 Drinks 类型,则返回 capacity 字段;如果是其他类型的商品,则不做进一步处理,不会返回 capacity,也不报错。有兴趣的读者,可以到 GraphQL 接口示例代码 看看。注意,GraphQL 引擎没有检测类型的能力,开发者必须为接口节点提供 resolveType 函数,以在运行时指定解析结果的类型!否则会报错:Abstract type NamedEntity must resolve to an Object type at runtime for field Query.users with value { id: 1, name: "foo", age: 1, type: "User" }, received "undefined". Either the NamedEntity type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function. ...

December 18, 2018 · 1 min · jiezi

使用 Gatsby.js 搭建静态博客 1 关键文件

原文地址:https://ssshooter.com/2018-12…静态博客之前也有搭建过,不过使用 Hexo 一键生成的,其实当时也有考虑过 Gatsby,不过这个框架搭建博客入门还是比较难的,前置知识点包括 react 和 graphQL。这个系列的文章记录的就是这个博客搭建中需要注意的点。此博客使用 gatsby-starter-blog 作为框架,后续自己添加功能。在安装 gatsby cli 后运行此指令即可以 gatsby-starter-blog 为模板创建博客。gatsby new gatsby-blog https://github.com/gatsbyjs/gatsby-starter-blog项目创建后文件夹结构基本如下(有区别是因为这是我搭建好的截图,也有可能是 starter 的版本升级)其中最为重要的是 gatsby-node.js、/src/templates/blog-post.js 以及 gatsby-config.js。gatsby-node.js页面创建逻辑大部分都在 gatsby-node.js,打开文件可以看到类似代码:// 页面创建函数exports.createPages = ({ graphql, actions }) => { const { createPage } = actions return new Promise((resolve, reject) => { const blogPostTemplate = path.resolve(src/templates/blog-post.js) // 查询 md 文件构建页面 // 此处查询使用的是 graphql,这也是 Gatsby 入门门槛较高的原因之一 // 不过其实这是一个比 sql 更容易理解的查询语言 resolve( graphql( { allMarkdownRemark(limit: 1000) { edges { node { frontmatter { path } } } } } ).then(result => { if (result.errors) { reject(result.errors) } // 遍历查询结果生成页面 result.data.allMarkdownRemark.edges.forEach(({ node }) => { const path = node.frontmatter.path // 生成单个页面的函数 createPage({ path, // 页面路径 component: blogPostTemplate, // 页面使用的模板 // 这是注入上下文变量,注入后可以在模板页面中使用变量 // 变量可以使用于 graphql 查询和 jsx 编写 context: { path, }, }) }) }) ) })}/src/templates/blog-post.js此处只是一个举例,其他模板文件和页面文件的结构都类似,所以这里使用 /src/templates/blog-post.js 说明文件结构。(另外放在 /src/pages/ 的 js 文件都是会转换为页面的)这类文件两部分:第一部分:export default BlogPostTemplate这是页面视图的组件,跟普通 jsx 一样,不过上面有说到:createPage 函数是可以注入参数到模板文件的。而这些参数就在 this.props.pageContext 中。另外,下面将会提到的页面查询函数所得的数据在 this.props.data。第二部分:export const pageQuery// 注意其中 $slug,这也是被页面创建函数注入的上下文变量,没有前缀,直接使用即可export const pageQuery = graphql query BlogPostBySlug($slug: String!) { site { siteMetadata { title author } } markdownRemark(fields: { slug: { eq: $slug } }) { id excerpt html frontmatter { title tags date(formatString: "MMMM DD, YYYY") } } }查询函数大概长这样,简单来说 graphql 就是把你需要的数据填入你的请求,然后返回给你,光说不易理解,自己玩一把就能立刻明白!更方便的是,在项目开发环境运行后,还会自带一个 graphql 查询页面:http://localhost:8000/___graphql一定要注意右上角是自带文档的!遇到数据结构懵逼的时候,在文档查一下就 ok 啦(你甚至可以 ctrl 点击 query 中的字段名直接跳转到对应文档,实在方便得不能再方便了,好评!)页面中的查询函数返回的结果会注入到 this.props.data,跟普通属性一样照常使用即可。gatsby-config.jsgatsby-config.js 看名字就知道这是 Gatsby 的配置文件。使用 starter 建立项目已经自带了不少插件,但在我的搭建过程中仍然有一些需要自己添加的。这里是 Gatsby 的插件库,遇到什么需求可以优先在此处搜索。总结结合这三个重要文件,便是 Gatsby 的应用结构:读取设置和插件 -> 调用创建页面前查询所需资源 -> 创建页面,把查询到的参数注入到模板 -> 进行模板本身的查询 -> 填入数据 -> 成功生成一个页面整个流程大部分都是使用循环生成所有页面。此系列下一篇将会是分页相关的详细说明,这是我初始化之后第一个加上的功能(是的, starter 是不带分页的…)。参考链接: https://www.gatsbyjs.org/docs… https://www.gatsbyjs.org/docs… ...

December 10, 2018 · 2 min · jiezi