🐡

GraphQL YogaのResolverに型をつけたい

2023/07/22に公開

GraphQL Yoga を使って個人開発をしています。
その中で記述した typeDefs に対して、resolver の型が保証されてほしかったのでやってみました。

困っていること

GraphQL yoga では以下のように schema を作成します。(コード例は 公式ドキュメントからコピペです)

import { createSchema } from "graphql-yoga";

export const schema = createSchema({
  typeDefs: /* GraphQL */ `
    type Query {
      hello: String
    }
  `,
  resolvers: {
    Query: {
      hello: () => "world",
    },
  },
});

ここで例えば hello の型を Int にしても、TypeScript の型上はエラーにはなりません。

// 略
  typeDefs: /* GraphQL */ `
    type Query {
      hello: Int # Int型に変更
    }
  `,
  resolvers: {
    Query: {
      hello: () => "world", // 型エラーにならない
    },
// 略

しかし、GraphQL の型では hello の resolver は Int 型の値を返すことを期待しているため、実行時エラーが発生します。

ERR Error: Int cannot represent non-integer value: "world"

typeDefs の型を変更したら、TypeScript の型上でエラーが出るようにしていきます。

やったこと

Resolver に型をつけるためには、記述した TypeDefs から Resolver に期待する型を generate する必要があります。
この生成に graphql-code-generator を利用します。

https://github.com/dotansimha/graphql-code-generator

また、TypeScript の Resolver の型を生成したいため、一緒に必要な Plugin も install します。

npm i -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-resolvers

install が完了後、下記コマンドで graphql-codegen の初期化と config の設定をします。(対話式で設定が始まります)

npx graphql-codegen init

初期化が完了したら、GraphQL Server を立ち上げた状態でコマンドを実行すると型が生成されます。

npm run codegen

これで指定した生成先の ts ファイルに Resolver の型が生成されるので、import して型を当てます。

import { createSchema } from "graphql-yoga";
import { Resolvers } from "../generated/graphql";

const resolvers: Resolvers = {
  Query: {
    hello: () => "world",
  },
};

export const schema = createSchema({
  typeDefs: /* GraphQL */ `
    type Query {
      hello: String
    }
  `,
  resolvers,
});

これで記述した typeDefs に対して resolver の型が保証されます。
試しに先程と同様に typeDefs を変更後、generate のコマンドを走らせると、

type Query {
  hello: Int # Int型に変更
}

しっかりと TypeScript Compiler が怒ってくれます。

これで typeDefs に対して正しい型が付けられた Resovler で開発ができるようになりました。

参考

Discussion