graphqlgen介绍:根据Graphql schema自动生成类型安全的resolver

graphqlgen 根据 Graphql schema 翻译出 resolver 的类型定义文件和脚手架模板。

这样就可以把繁琐的写 resolver 样板代码的工作自动完成了。

prisma 的自动化因此由 50%提升到 75%,而且因为自动化,coding 起来更加安全方便。

类型安全为开发人员带来了很多好处。 最值得注意的是, 编译时错误检查自动完成使开发人员对代码充满信心并提高了工作效率。

如果没有类型安全性,很容易引入小错别字或类似可避免的错误,最终需要花费数小时的调试时间。 如何证明类型安全的潜在好处?

看图找错:

GraphQL resolver 实现中有五个错误:

  1. 无法正确访问login resolver 的查询参数。 访问它们的正确方法是通过args.input(例如args.input.password),因为它们包含在输入对象中。
  2. args.usernamelogin resolver 中写入全小写,同时在 schema 中使用 camelcase 表示法编写。
  3. 缺少 Mutation 类型的注册 resolver。
  4. 缺少 User 类型的 userName resolver。 请注意,蓝色框中的示例用户表示由我的 resolver 返回的用户对象的形状。 这就是 id 和 name resolver 有效但 username 没有的原因(因为 casing 不匹配)。
  5. profilePictureUrl resolver 违反了 schema 中定义的非 null 约束。

你花了多少时间寻找解决方案,以及你实际发现了多少问题? 如果 resolver 完全是类型安全的,那么你不需要花费一秒钟来识别这些问题,而只需让编译器在编译时为你捕获它们。

我们构建了graphqlgen来帮助你使 resolver 类型安全。

在深入研究构建 GraphQL 服务器时出现的一些典型问题之前,让我们简要回顾一些相关的概念:GraphQL types, models, resolvers

在上图中,我们看到了schema.graphql中定义的 GraphQL types。

resolver 在右侧的resolvers.ts实现。 请注意,city resolver 的返回值是 City resolver 的输入参数(父级)。

模型在models.ts中定义,表示通过 resolver 链传递的对象。 它们由一个 resolver 返回,并再次作为 resolver 树中后续 resolver 的parent参数找到(参见蓝色标记的区域)。

问题:保持 GraphQL schema 定义与相应的 resolver 同步是复杂的任务,并且随着项目的增长而变得越来越复杂。问题主要发生在命名不一致(例如拼写错误或错误符号),或者直接忘记实现整个 resolver 功能。

解决方案:使用模式优先方法开发 GraphQL 服务器。这意味着 GraphQL schema 始终是真实的来源,并且 resolver 完全基于 schema 定义实现。在使用模式优先时,使用从 GraphQL schema 定义派生 resolver 接口的正确工具是关键。

问题:resolver(嵌套)GraphQL 查询的过程涉及多个 resolver“执行级别”,其中前一个执行级别的返回值是下一个执行级别的输入。确保 resolver 的返回值与parent参数的预期结构匹配是至关重要的 - 如果不是这种情况,则 GraphQL 服务器会在运行时爆炸。

解决方案:引入类型安全模型,表示 resolver 的返回值和parent参数。使用此方法,编译器可确保先前执行级别的返回值始终与相应parent参数的所需结构匹配。

问题:确保你的 resolver 完全是类型安全的,需要大量的样板代码。保持该样板与 GraphQL schema 同步是一个非常麻烦且容易出错的过程。在下面了解使 resolver 类型安全所需的样板文件。

查看所需的样板:

键入 resolver 参数并且返回值

GraphQL resolver 通常会收到四个输入参数,这些参数都需要输入:

  1. parent:上一层 resolver 执行级别的返回值了解更多
  2. args:客户端提交的 GraphQL 查询参数
  3. context:通过 GraphQL resolver 链传递的对象
  4. info:携带查询的 AST了解更多

默认的 resolver 实现

使用纯 JavaScript 构建 GraphQL 服务器时,可以省略默认的 resolver 实现。 作为示例,请考虑此 GraphQL schema:


type Query {
  users: [User!]!
}
type User {
  id: ID!
  name: String!
}

使用 TypeScript 时,你必须实现 id 和 name 的 resolver:


const resolvers = {
  Query: {
    users: () => db.getUsers()
  },
  User: {
    id: parent => parent.id,
    name: parent => parent.name
  }
}

使用纯 JavaScript 时,这些默认的 resolver 实现可以省略,因为它们是由 graphql-js 推断的。

解决方案:可以自动生成样板。通常,所需的样板代码是基于一些简单的规则从 GraphQL schema 派生的。为了避免在将 GraphQL schema 转换为相应的类型定义时出现人为错误,应该自动执行此过程,并且应使用代码生成自动生成样板。

上述所有问题都可以通过适当的工作流程和工具来解决! 定义这些工作流程并构建这些工具是 Prisma 的核心目标之一。 今天,我们很高兴地宣布 graphqlgen,一个帮助你实现类型安全 resolver 的工具。 这是你可以用它做的:

  • 生成类型定义代码(用于 resolver 输入参数和返回值)和默认的以确保类型安全的 resolver
  • 由开发人员完成的脚手架 resolver“骨架”

你可以使用以下命令安装 graphqlgen:


cnpm install -g graphqlgen

graphqlgen docs

两种方式开始:

  1. 添加 graphqlgen 到已有项目here
  2. 从零开始(看下面)

如果要将 graphqlgen 添加到现有项目,可以使用 graphqlgen --init 命令创建graphqlgen.yml的初始版本。

开始使用 graphqlgen 的最快方法是使用 npm init-initializer 建立 fully-typed GraphQL server:


npm init graphqlgen ./my-graphql-server/

这将创建 my-graphql-server 目录,其中包含 GraphQL 服务器的代码,包括使用 graphqlgen 的设置。 graphqlgen CLI 要求你在项目中提供 graphqlgen.yml 配置文件。

示例:


# 生成代码的语言
language: typescript
# 你的 GraphQL schema 的路径
schema: ./src/schema.graphql
# Map SDL types from the GraphQL schema to TS models
models:
  files:
    - ./src/types.ts
# 生成resolver的类型定义和默认生成的resolver
# DO NOT EDIT THIS FILE不要改这个文件
output: ./src/generated/graphqlgen.ts
# 临时搭建的 resolver可以复制并粘贴到你的应用程序中
resolver-scaffolding:
  output: ./src/generated/tmp-resolvers/
  layout: file-per-type
### 生成代码

要调用代码生成过程,请运行 graphqlgen 命令:

这将从graphqlgen.yml读取配置并将生成的代码存储在:

  • ./src/generated/graphqlgen.ts:包含 resolver 参数和返回值的类型的文件。 还包括 resolver 默认实现。 此文件不需要手动编辑,需要在每次更改 GraphQL schema 时重新生成。
  • ./src/generated/tmp-resolvers/:包含 resolver“skeletons”的目录。 生成的文件是临时的。 生成的文件中的代码将被复制并粘贴到你当前的 GraphQL 服务器实现中。
  • 见例子here

注意:graphqlgen CLI 也可以通过我们游戏玩家之间的 gg 命令别名调用 🤓

graphqlgen 可以在你需要为 GraphQL schema 引入更改时为你提供帮助,例如:

  • 向 GraphQL API 添加新操作(即向 Query,Mutation 或 Subscription 类型添加字段)。
  • 更新 GraphQL schema 中的类型,例如 添加,重命名或删除类型上的字段。
  • 从模型中删除字段并更新 resolver。

观看此视频,了解 graphqlgen 的运行情况(向 Ben Awad 致敬 🙏):

虽然 graphqlgen 已准备好投入生产,但尚未达到 1.0。 配置文件graphqlgen.yml的结构方式可能会发生变化,但主要功能将保持不变。

graphlgen 目前支持 TypeScript,但对 Flow 和 Reason 的支持已经开始了。 我们还计划为 graphlgen 引入一个插件系统,这样就可以与其他工具(如 Prisma 或 Apollo)进行更紧密的集成。

我们很高兴听到你的想法! 随意提供有关 GitHub 的反馈或加入我们的微信群进行深入讨论。

返回