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的反馈或加入我们的微信群进行深入讨论。

返回