💎

graphql-codegen は validation 用の schema も自動で生成できる (yup と zod)

2022/01/31に公開1

GraphQL Code Generator (a.k.a. graphql-codegen) のプラグインとして graphql-codegen-typescript-validation-schema (Star ください!) を利用すると yupzod といったフロントエンド validation 用の schema も自動で生成できます。

例えばこのような GraphQL Schema を与えます。ここで記述している constraint directive は confuser/graphql-constraint-directive で提供されているものを想定してます。

input ExampleInput {
  email: String! @required(msg: "Hello, World!") @constraint(minLength: 50, format: "email")
  message: String! @constraint(startsWith: "Hello")
}

directive @required(
  msg: String
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION

この Schema を想定した設定を次のように記述します。

generates:
  path/to/graphql.ts:
    plugins:
      - typescript
      - typescript-validation-schema # 今回利用するプラグイン
    config:
      # typescript plugin の設定
      # see: https://www.graphql-code-generator.com/plugins/typescript
      strictScalars: true
      # typescript-validation-schema の設定。typescript プラグインの設定と混同できます。
      schema: yup # or zod
      directives:
        # ここでは graphql の directive の情報を書きます。例えば
        #
        # directive:
        #   arg1: schemaApi
        #   arg2: ["schemaApi2", "Hello $1"]
        #
        # より多くの例は `./tests/directive.spec.ts` にあります。
        # https://github.com/Code-Hex/graphql-codegen-typescript-validation-schema/blob/main/tests/directive.spec.ts
        required:
          msg: required
        constraint:
          minLength: min
          # $1 と指定された constraint directive の `startsWith` 引数の値を置き換えます
          startsWith: ["matches", "/^$1/"]
          format:
            email: email

設定を元に生成される path/to/graphql.ts の中身は次のようになります。

export function ExampleInputSchema(): yup.SchemaOf<ExampleInput> {
  return yup.object({
    email: yup.string().defined().required("Hello, World!").min(50).email(),
    message: yup.string().defined().matches(/^Hello/)
  })
}

めっちゃ便利ですね!

もちろん生成された yup schema, zod schema を上書きして利用することも可能です。各 schema の上書き方法については example directory のそれぞれの directory の中に README.md を用意したのでそれらを参考にしてください。

より詳しい設定の説明は Config API Reference に記述しているので読んでみてください。

そもそもなんで作ったの?

TypeScript を使って GraphQL Schema first な開発をする場合 GraphQL Code Generator を利用することが多いと思います。

筆者は元々 GraphQL の Schema から TypeScript のコードを生成し、フロントエンドのフォームバリデーションに利用する validation schema を手書きしていました。書くたびにその API を調べたり、同じようなコードを繰り返し記述することにとても面倒な気持ちを抱いていました。そこで、型を生成できるなら validation schema も一緒に生成し、必要な部分だけ上書きして利用しようと考えるようになりました。

検索してみるとやりたいことを実現できそうなプラグインは既にいくつか存在していました。

しかし、これらのプラグインは TypeScript に適していなかったり、プラグイン側で想定された directive に対してのみ動作しないものしかありませんでした。 validation を行うための directive を既に用意していたこともあり、それをわざわざプラグインに合わせて修正するのもどうかと思っていました。

自分が求めているものが作られなさそう、二度手間開発を一刻も早く脱出したかったので思い切って作成することにしました。

npm を使ったパッケージ配布をしたことがなかったので、この挑戦は非常に気合いが必要でした。

最後に

バグや実現して欲しい要望があれば issues や pull request をぜひ投稿して下さい!
Twitter アカウント @codehex 宛でも構いません。

また、個人的な事情ですが GitHub で筆者の Sponsor になってくれる方を募集しています。今後の開発の励みになるので、そちらの方でも応援していただけると幸いです。

Discussion

みんてぃみんてぃ

簡単に使ってみましたがよかったです!
mutation 用に毎回 zod を書くのが面倒なため、いいものがないかよさそうなものを探していたのでちょうどよかったです。
細かい調整が必要ですが個人アプリに組み込んでみようと思います。