KJ DEV
How to

ExpressのGraphQLで相互のRelation関係にあるTypeをimportする方法

ExpressでGraphQLを実装している時に、TypeでRelationの関係を作ろうとして

1
Error: Expected undefined to be a GraphQL type

というエラーに出会いました。

原因はType同士でimportしていたために、一方のTypeがundefinedになってしまうことです。

この問題に対応してみました。

目次
  1. GraphQLのType同士で循環参照する場合
  2. fieldsではオブジェクトではなく関数で返す

GraphQLのType同士で循環参照する場合

まず今回エラーが発生したコードは書きのようなものです。

それぞれのTypeからお互いをimportしています。

1
2
3
4
5
6
7
8
9
10
11
import UserType from './UserType';

const PostType = new GraphQLObjectType({
  name: 'Post',
  fields: {
    title: { type: GraphQLString },
    user: { type: UserType }
  }
});

export default PostType;
1
2
3
4
5
6
7
8
9
10
11
import PostType from './PostType';

const UserType = new GraphQLObjectType({
  name: 'User',
  fields: {
    name: { type: GraphQLString },
    posts: { type: new GraphQLList(PostType) }
  }
});

export default UserType;

お互いをimportしている循環参照の関係にあるため、当然ですがこのコードでは先に読み込まれる方が、読み込み先のTypeをundefinedとして認識します。

ただGraphQLでTypeを定義しているとこういうコードは避けられないと思う一方で、どのような風に対策するのがよいのか。

fieldsではオブジェクトではなく関数で返す

fieldsはオブジェクトではなく、オブジェクトを関数を指定できます。

関数で返すことをfieldsの部分が遅延評価されるようになり、先に書いたように読み込んだ時点ではundefinedでもエラーが発生しなくなります。

コードとしては下記のような形です。

1
2
3
4
5
6
7
8
9
const PostType = new GraphQLObjectType({
  name: 'Post',
  fields: {
    title: { type: GraphQLString },
    user: { type: UserType }
  }
});

export default PostType;
1
2
3
4
5
6
7
8
9
const UserType = new GraphQLObjectType({
  name: 'User',
  fields: {
    name: { type: GraphQLString },
    posts: { type: new GraphQLList(PostType) }
  }
});

export default UserType;

わかってしまえばなんてことないけど、少しハマってしまいました・・。

開発で参考になった本

実際に読んでみて開発に役立った本を紹介しています。

これから本格的にデザインシステムを学んで作りたい時にとても参考になる一冊でした。デザインシステムついて幅広く触れられているけど、「tailwindを触ってデザインシステムに興味を持った」という人でも少しずつ取り入れやすいです。