UnionsとEmums(列挙型)
GraphQLにおける
Union
型はよくInterface
に特徴が類似しています。しかし、型の間で共通のフィールドを指定できません。Union
型(以下、ユニオン型と表記)は1つのフィールドからバラバラのデータ型を返すのに便利です。GraphQLのユニオン型を定義するには、このユニオンが構成されるクラスを定義しなければなりません。まず最初に、
Book
とAuthor
という2つのクラスを作成します。import { Field, ObjectType } from '@nestjs/graphql';
// Book
@ObjectType()
export class Book {
@Field()
title: string;
}
// Author
@ObjectType()
export class Author {
@Field()
name: string;
}
上記の状態で、
@nestjs/graphql
パッケージからエクスポートされたcreateUnionType
関数を使用してResultUnion
ユニオンを登録します。export const ResultUnion = createUnionType({
name: 'ResultUnion',
types: () => [Author, Book] as const,
});
注意
createUnionType
関数のtypes
プロパティで返される配列には、const
を付与する必要があります。const
が与えられていないと、コンパイル時に誤った宣言ファイルが生成され、他のプロジェクトから使用する際にエラーとなります。これで、クエリの中で
ResultUnion
を参照できるようになりました。@Query(returns => [ResultUnion])
search(): Array<typeof ResultUnion> {
return [new Author(), new Book()];
}
これにより、SDLでGraphQLスキーマの以下の部分が生成される。
type Author {
name: String!
}
type Book {
title: String!
}
union ResultUnion = Author | Book
type Query {
search: [ResultUnion!]!
}
ライブラリが生成するデフォルトの
resolveType
関数は、resolver
メソッドから返された値を基に型を抽出します。つまり、リテラルなJavaScriptオブジェクトではなく、クラスインスタンスを返すことが義務付けられているのです。カスタマイズされた
resolveType()
関数を提供するには、以下のようにcreateUnionType
関数に渡されるオプション・オブジェクトに resolveType
プロパティを渡してください。export const ResultUnion = createUnionType({
name: 'ResultUnion',
types: () => [Author, Book] as const,
resolveType(value) {
if (value.name) {
return Author;
}
if (value.title) {
return Book;
}
return null;
},
});
スキーマファーストのアプローチでユニオンを定義するには、SDLでGraphQLユニオンを作成するだけで構いません。
type Author {
name: String!
}
type Book {
title: String!
}
union ResultUnion = Author | Book
export class Author {
name: string;
}
export class Book {
title: string;
}
export type ResultUnion = Author | Book;
ユニオンはリゾルバマップにおいて、ユニオンがどのタイプに解決されるべきかを決定するために、余分な
__resolveType
フィールドを必要とします。また、ResultUnionResolver
クラスは、どのモジュールにもプロバイダとして登録されなければならないことに注意してください。ResultUnionResolver
クラスを作成し、__resolveType
メソッドを定義してみましょう。@Resolver('ResultUnion')
export class ResultUnionResolver {
@ResolveField()
__resolveType(value) {
if (value.name) {
return 'Author';
}
if (value.title) {
return 'Book';
}
return null;
}
}
メモ
すべてのデコレータは
@nestjs/graphql
パッケージからエクスポートされる。列挙型は、特定の値のグループ内に制限された特殊なスカラーです。これにより、主に以下のことが可能になります。
- この型の引数が与えられている値のいずれかであることを確認すること
- フィールドが常に有限の値の集合の1つであることを、型システムを通じて伝達すること
コードファーストのアプローチを使用する場合、TypeScriptの
enum
を作るだけでGraphQLのenum
型を定義できます。export enum AllowedColor {
RED,
GREEN,
BLUE,
}
この状態で、
@nestjs/graphql
パッケージからエクスポートされたregisterEnumType
関数を活用してAllowedColor
型のenum
を登録していきます。registerEnumType(AllowedColor, {
name: 'AllowedColor',
});
これで、
AllowedColor
を型の中で参照できるようになりました。@Field(type => AllowedColor)
favoriteColor: AllowedColor;
これにより、SDLでGraphQLスキーマの以下の部分が生成されます。
enum AllowedColor {
RED
GREEN
BLUE
}
enum
の説明を記述するには、registerEnumType
関数にdescription
プロパティを渡します。registerEnumType(AllowedColor, {
name: 'AllowedColor',
description: 'The supported colors.',
});
enum
の値に説明をつけたり、値を非推奨としてマークするには、以下のようにvaluesMap
プロパティを指定します。registerEnumType(AllowedColor, {
name: 'AllowedColor',
description: 'The supported colors.',
valuesMap: {
RED: {
description: 'The default color.',
},
BLUE: {
deprecationReason: 'Too blue.',
},
},
});
このプログラムの場合、SDLで以下のようなGraphQLスキーマが生成されます。
"""
The supported colors.
"""
enum AllowedColor {
"""
The default color.
"""
RED
GREEN
BLUE @deprecated(reason: "Too blue.")
}
スキーマファーストのアプローチで
enum
を定義するには、SDLでGraphQLのenum
を作成するだけです。enum AllowedColor {
RED
GREEN
BLUE
}
そして、型付け生成機能を使って、対応するTypeScriptの定義を次のように作成できます。
export enum AllowedColor {
RED
GREEN
BLUE
}
バックエンドが、内部的に公開APIと異なる値を
enum
に強制することがあります。この例では、APIにRED
が含まれているが、リゾルバでは代わりに#f00
を使用することができます。これを実現するには、AllowedColor
enum用のリゾルバオブジェクトを宣言します。 export const allowedColorResolver: Record<keyof typeof AllowedColor, any> = {
RED: '#f00',
};
メモ
全てのデコレータは
@nestjs/graphql
パッケージからエクスポートされます。そして、このリゾルバオブジェクトを
GraphQLModule#forRoot()
メソッドのresolvers
プロパティと一緒に 、以下のように使用します。GraphQLModule.forRoot({
resolvers: {
AllowedColor: allowedColorResolver,
},
});
Last modified 9mo ago