第十期基于 ApolloKoa 搭建 GraphQL 服务端

Posted 水煮前端

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十期基于 ApolloKoa 搭建 GraphQL 服务端相关的知识,希望对你有一定的参考价值。


本文预期读者对 NodeJS、Koa 有一定的了解

GraphQL 解决了什么问题

过去,服务端的研发人员设计一个数据接口,通常并不会要求使用接口的客户端研发人员知道接口内部的数据结构,而是只提供一份 api 文档(使用说明书),文档内容介绍如何调用 API,返回什么数据,文档和功能都实现后,就算完成服务端工作了。

我们使用这个工作方式工作,慢慢地发现了一些问题:

专门写 API 文档成了一种负担API 文档和 API 服务经常部署在不同的域名,我们需要记住文档在哪我们总是发现 API 的实际行为和文档不一致API 内部数据的枚举值,总是泄露到客户端API 参数校验工作在客户端和服务器重复进行我们很难看到整个应用数据的结构图我们不得不维护多个 API 版本

慢慢地,我们发现,在服务端和客户端之间,需要共享一份数据描述规范:

这份数据描述就是功能的一部分(注意,它不是注释),它参与实现 API 功能。这份数据描述本身就是文档,我们不在需要专门写文档,更不需要专门去部署文档服务。当我们修改了数据描述细节,API 功能就会发生变化,我们无需担心文档和行为不一致的问题。数据描述本身支持枚举类型,限制枚举值泄露的问题。数据描述本身有类型系统,我们无需在客户端和服务器重复做参数校验工作。数据描述本身就是整个应用数据的结构图。数据描述能屏蔽版本维护的问题。

GraphQL 就是这么一种数据描述规范。

什么是 GraphQL

官网的介绍如下:

GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。

下面是一个基于 GraphQL 的数据描述:

type Query { book: Book}
enum BookStatus { DELETED NORMAL}
type Book { id: ID name: String price: Float status: BookStatus}

为了不和特定的平台绑定,且更容易理解服务端的功能,GraphQL 实现了一个易读的 schema 语法: Schema Definition Language (SDL)

SDL 用于表示 schema 中可用的类型,以及这些类型之间的关系

SDL 必须以字符串的形式存储

SDL 规定了三类入口,分别为:

Query 用于定义操作 (可以理解为 CURD 中的 R)Mutation 用于定义操作 (可以理解为 CURD 中的 CUD)Subscription 用于定义长链接(基于事件的、创建和维持与服务端实时连接的方式)

通过上述代码,我们声明了一个查询,名为 book,类型为 Book

类型 Book 拥有四个字段,分别为:

id, 代表每本书的唯一id, 类型为 IDname, 代表每本书的名字, 类型为字符串price, 代表每本书的价格, 类型为浮点数status, 代表每本书的状态, 类型为 BookStatus

BookStatus 是一个枚举类型,包含:

DELETED 代表书已经下架,它的值为 0NORMAL 代表书在正常销售中, 它的值为 1

除了可以定义自己的数据类型外,GraphQL 还内置了一下几种基础类型(标量):

Int: 有符号 32 位整型Float: 有符号双精度浮点型String: UTF-8 字符序列Boolean: true 或 falseID: 一个唯一的标识,经常用于重新获取一个对象或作为缓存的 key

这里需要注意,GraphQL 要求端点字段的类型必须是标量类型。(这里的端点可以理解为叶子节点)

关于 GraphQL 的更多信息,请参考:https://graphql.cn/learn/

什么是 Apollo

官网的介绍如下:

Apollo 是 GraphQL 的一个实现,可帮助您管理从云到 UI 的数据。它可以逐步采用,并在现有服务上进行分层,包括 REST API 和数据库。Apollo 包括两组用于客户端和服务器的开源库,以及开发人员工具,它提供了在生产中可靠地运行 GraphQL API 所需的一切。

我们可以将 Apollo 看作是一组工具,它分为两大类,一类面向服务端,另一类面向客户端。

其中,面向客户端的 Apollo Client 涵盖了以下工具和平台:

React + React NativeAngularVueMeteorEmberios (Swift)android (Java)...

面向服务端的 Apollo Server 涵盖了以下平台:

JavaScalaRubyElixirNodeJS...

我们在本文中会使用 Apollo 中针对 NodeJS 服务端 koa 框架的 apollo-server-koa 库

关于 apollo server 和 apollo-server-koa 的更多信息请参考:

https://www.apollographql.com/docs/apollo-server/https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-koa

搭建 GraphQL 后端 api 服务

快速搭建

step1:

新建一个文件夹,我这里新建了 graphql-server-demo 文件夹

mkdir graphql-server-dem

在文件夹内初始化项目:

cd graphql-server-demo && yarn init

安装依赖:

yarn add koa graphql apollo-server-koa

step2:

新建 index.js 文件,并在其中撰写如下代码:

'use strict'
const path = require('path')const Koa = require('koa')const app = new Koa()const { ApolloServer, gql } = require('apollo-server-koa')
/** * 在 typeDefs 里定义 GraphQL Schema * * 例如:我们定义了一个查询,名为 book,类型是字符串 */const typeDefs = gql` type Query { book: Book hello: String }
enum BookStatus { DELETED NORMAL }
type Book { id: ID name: String price: Float status: BookStatus }`;
const BookStatus = { DELETED: 0, NORMAL: 1}/** * 在这里定义对应的解析器 * * 例如: * 针对查询 hello, 定义同名的解析器函数,返回字符串 "hello world!" * 针对查询 book,定义同名的解析器函数,返回预先定义好的对象(实际场景可能返回来自数据库或其他接口的数据) */const resolvers = {
// Apollo Server 允许我们将实际的枚举映射挂载到 resolvers 中(这些映射关系通常维护在服务端的配置文件或数据库中) // 任何对于此枚举的数据交换,都会自动将枚举值替换为枚举名,避免了枚举值泄露到客户端的问题 BookStatus,
Query: {
hello: () => 'hello world!',
book: (parent, args, context, info) => ({ name:'地球往事', price: 66.3, status: BookStatus.NORMAL })
}};
// 通过 schema、解析器、 Apollo Server 的构造函数,创建一个 server 实例const server = new ApolloServer({ typeDefs, resolvers })// 将 server 实例以中间件的形式挂载到 app 上server.applyMiddleware({ app })// 启动 web 服务app.listen({ port: 4000 }, () => console.log(`

以上是关于第十期基于 ApolloKoa 搭建 GraphQL 服务端的主要内容,如果未能解决你的问题,请参考以下文章

华为云PB级数据库GaussDB(for Redis)揭秘第十期:GaussDB(for Redis)迁移系列(上)

华为云PB级数据库GaussDB(for Redis)揭秘第十期:GaussDB(for Redis)迁移系列(上)

时速云企业级容器PaaS技术沙龙 第十期上海站

CSDN编程竞赛 ——— 第十期

艺术编程-技术之声第十期

第十期 华为拓扑-OSPF配置