GraphQL で配列が nullable になって扱いにくすぎる件を何とかする
はじめに
【全部俺】 Web フロントエンドエンジニアのメモ Advent Calendar 2022 22 日目の記事です。
GraphQL のスキーマに配列が含まれると GraphQL Code Generator で nullable になってしまい、フロントエンドで扱いにくい問題の対処方法を解説します。
背景
REST しかやったことない人間が GraphQL のスキーマを見よう見まねで書いてみました。
type BlogPost {
slug: string!
}
query Query {
allBlogPost: [BlogPost]
}
このスキーマを GraphQL Code Generator で型生成するとこのような型が生成されます。
export type Maybe<T> = T | null;
export type Query = {
__typename?: "Query";
allBlogPost?: Maybe<Array<Maybe<BlogPost>>>;
};
allBlogPost は BlogPost の配列 (空配列を含む) のイメージだったのですが、実際は下記の 5 パターンが返ってくる可能性のあるスキーマになってしまいました。パターンが増えるので考えることが増えてしまい、開発効率が低下してしまいます。(プログラムが牢固になるという利点はありますが...)
意外に思ったのが、配列の中に null が入るパターンです。 GraphQL スキーマではエクステンションマークを明示的に付けない場合は nullable になるのでこのような型になります。
- {}
- {allBlogPost: null}
- {allBlogPost: []}
- {allBlogPost: [null]}
- {allBlogPost: [{slug: "slug"}]}
これで slug 一覧を生成しようとおもったらこのような感じでしょうか..。
data?.allBlogPost
?.filter((v): v is NonNullable<typeof v> => v !== null)
.map((v) => v.slug) ?? [];
null を許容しないスキーマに変更する
GraphQL のドキュメントを参考に、エクステンションマークを付けて non-nullable にしてみました。配列の内外共にエクステンションマークを付けるようにします。
Schemas and Types | GraphQL
https://graphql.org/learn/schema/
query Query {
allBlogPost: [BlogPost!]!
}
このスキーマを GraphQL Code Generator で型生成するとこのような型が生成されます。
export type Query = {
__typename?: "Query";
allBlogPost: <Array<BlogPost>>;
};
パターンが絞られ、必ず配列が返るようになります。
- {allBlogPost: []}
- {allBlogPost: [{slug: "slug"}]}
これならシンプルに実装できます。
data.allBlogPost.map((v) => v.slug);
バックエンド側でも null を返さないよう実装するように仕様が明確化されます。
まとめ
明示的に non-nullable を指示することで、実装をシンプルにできました。