GraphQL Mesh是为了解决什么问题而创建的?~ 通过GraphQL将Qiita API包装起来来深入理解GraphQL Mesh ~
GraphQL Mesh 是什么?
GraphQL Mesh 在 The Guild 宣布发表了。
? GraphQL Mesh – 任意查询,随时随地运行 ?
? 我非常自豪地宣布我们的新开源库 – GraphQL Mesh!使用 #GraphQL 进行查询:
? openapi/Swagger
? gRPC
? SOAP
? SQL
? GraphQL
? 更多!
无需修改源代码!
线程 1/5 pic.twitter.com/xo0G5smUwp— Urigo (@UriGoldshtein) March 23, 2020
GraphQL Mesh 是一个作为与现有后端 API 服务(如 REST API 和 gRPC)连接的代理的功能。
GraphQL Mesh 被设计成使开发人员能够通过 GraphQL 查询轻松访问使用其他 API 规范(如 gRPC、OpenAPI、Swagger、oData、SOAP、GraphQL 等)描述的服务。
以前,为了实现GraphQL代理,需要对后端API服务进行以下操作。
-
- その API 仕様を読み解き、
-
- GraphQL サーバを構築し、
- スキーマ、リゾルバ、バックエンド API との通信処理を実装する
我为了实现一个包装多个后端API的GraphQL服务器耗费了大量的努力。
当然,像 openapi-to-graphql 这样的工具可以将 OpenAPI 定义转换为 GraphQL 模式,还有像 graphql-tools 这样根据模式定义构建模拟服务器的工具,已经出现了。
新出现的 GraphQL Mesh 是一种革命性的工具。只要有后端 API 的 API 规范,就可以获得一个可以立即执行 GraphQL 查询的 GraphQL 代理来访问该后端 API。
本篇文章将介绍GraphQL Mesh的简单使用方法和架构设计模式。
※ 本篇文章参考自这篇文章。
用法
假设存在使用OpenAPI编写的REST API服务作为后端,我们将使用GraphQL Mesh构建代理服务器。本次将使用Qiita API作为后端API。
1. 安装
GraphQL Mesh 需要将几个核心库组合安装。
$ yarn add graphql \
@graphql-mesh/runtime \
@graphql-mesh/cli \
@graphql-mesh/openapi
截止至3月25日,可使用的API(以及计划中的API)如下所示。
@graphql-mesh/graphql
AvailableGraphQL endpoint (schema-stitching, based on graphql-tools-fork
)@graphql-mesh/federation
WIPApollo Federation services@graphql-mesh/openapi
AvailableSwagger, OpenAPI 2/3 (based on openapi-to-graphql
)@graphql-mesh/json-schema
AvailableJSON schema structure for request/response@graphql-mesh/postgraphile
AvailablePostgres database schema@graphql-mesh/grpc
AvailablegRPC and protobuf schemas@graphql-mesh/soap
AvailableSOAP specification@graphql-mesh/mongoose
AvailableMongoose schema wrapper based on graphql-compose-mongoose
@graphql-mesh/odata
WIPOData specification2. 在设定文件中描述后端 API 的 API 规范
然后,我们创建一个名为.meshrc.yaml的文件,并描述后端API的API规范。在这个例子中,我们将使用OpenAPI。此外,我们还支持gRPC,oData,SOAP,GraphQL等其他协议。.meshrc.yaml文件应放置在项目的根目录中。
sources:
- name: Qiita
handler:
openapi:
source: ./qiita.openapi.yaml
QiitaAPI的OpenAPI定义中的.qiita.openapi.yaml如下所示。
info:
version: 0.0.1
title: Qiita API
host: “qiita.com”
basePath: “/api/v2”
schemes:
– https
consumes:
– application/json
produces:
– application/json
paths:
“/tags/{tagId}/items”:
get:
parameters:
– in: path
name: tagId
type: string
required: true
– $ref: “#/parameters/pageParam”
– $ref: “#/parameters/perPageParam”
responses:
“200”:
description: 返回以标签降序排列的帖子列表。
schema:
title: 标签文章列表
type: array
items:
$ref: “#/definitions/Item”
“/users/{userId}”:
get:
parameters:
– in: path
name: userId
type: string
required: true
responses:
“200”:
description: 获取用户信息。
schema:
$ref: “#/definitions/User”
“/users/{userId}/items”:
get:
parameters:
– in: path
name: userId
type: string
required: true
– $ref: “#/parameters/pageParam”
– $ref: “#/parameters/perPageParam”
responses:
“200”:
description: 返回用户的帖子列表。
schema:
title: 用户文章列表
type: array
items:
$ref: “#/definitions/Item”
“/items”:
get:
parameters:
– $ref: “#/parameters/pageParam”
– $ref: “#/parameters/perPageParam”
– name: query
in: query
description: 搜索查询
required: false
type: string
responses:
“200”:
description: 返回帖子列表。
schema:
title: 文章列表
type: array
items:
$ref: “#/definitions/Item”
parameters:
pageParam:
in: query
name: page
description: 页码(1至100)
type: number
perPageParam:
in: query
name: per_page
description: 每页显示的项目数(1至100)
type: number
definitions:
ErrorMessage:
description: 包含错误消息的message属性和表示错误类型的type属性。
type: object
properties:
message:
type: string
type:
type: string
Group:
description: 表示Qiita:Team的小组。
type: object
properties:
created_at:
type: string
id:
type: integer
name:
type: string
private:
type: boolean
updated_at:
type: string
url_name:
type: string
Tag:
description: 标签
properties:
name:
type: string
example: Ruby
versions:
type: array
items:
type: string
example: 0.0.1
User:
properties:
description:
description: 自我介绍
type: string
facebook_id:
type: string
followees_count:
description: 关注该用户的用户数
type: integer
followers_count:
description: 该用户的关注者数
type: integer
github_login_name:
type: string
id:
type: string
items_count:
description: “该用户在qiita.com上发布的公开帖子数量(不包括Qiita:Team上的帖子)”
type: integer
linkedin_id:
type: string
location:
type: string
name:
type: string
organization:
type: string
permanent_id:
description: 用户的整数ID
type: integer
profile_image_url:
description: 用户设置的个人资料图片URL
type: string
twitter_screen_name:
type: string
website_url:
type: string
Item:
type: object
properties:
rendered_body:
type: string
body:
type: string
coediting:
type: boolean
comments_count:
type: integer
created_at:
type: string
id:
type: string
likes_count:
type: string
private:
type: boolean
reactions_count:
type: integer
title:
type: string
updated_at:
type: string
url:
type: string
page_views_count:
type: integer
tags:
type: array
items:
$ref: “#/definitions/Tag”
user:
$ref: “#/definitions/User”
group:
$ref: “#/definitions/Group”
启动 GraphQL Mesh 服务器
建议将GraphQL Mesh服务器启动。以下命令可考虑设置为npm脚本。
$ yarn graphql-mesh serve
yarn run v1.22.4
info: ?️ => Serving GraphQL Mesh GraphiQL: http://localhost:4000/
请在浏览器中打开 http://localhost:4000/ 来启动 GrapiQL 并进行确认。
执行 GraphQL 查询
GraphQL的真骨骼在于通过嵌套描述多个REST API可以获取的信息,从而同时获取Qiita文章的信息和与文章相关的用户信息,这一切都可以在一次查询中完成。
query getItems {
getItems{
title
likesCount
user {
name
itemsCount
organization
description
}
}
}
看起来已经正确地获取到了。
此外,能准确解读 OpenAPI 模型的定义,并且能将其正确地映射到 GraphQL 的模式定义中,这真是太棒了。
GraphQL Mesh 的使用方式
GraphQL Mesh充当后端API的代理。由于这个特性,它可以作为客户端的网关,并且可以组合多个后端进行配置。
另外,当多个微服务进行内部相互通信时,也可以选择采用HUB结构。
这个项目似乎还处于开发的初期阶段,根据GitHub的README文件中记载如下。
注意:该项目还处于早期阶段,未来可能会有重大变化。
未来可能会有重大变更。然而,我对这个工具的核心概念非常受到感动。如果像AWS的AppSync这样的GraphQL托管服务也采用这种思想,将对Web API行业产生重大影响。