Interface

Interface(インターフェイス)

多くの型システムと同様に、GraphQLはインターフェイスをサポートしています。インターフェイスは、インターフェイスを実装するために型が含まなければならないフィールドのセットを含む抽象的な型です。(ざっくりTypeScriptのinterfaceと同じイメージで解釈してもらっても大丈夫です)

コードファースト

コードファーストの場合、@nestjs/graphqlからエクスポートされる@InterfaceType()デコレータでアノテーションされた抽象クラスを作成することで、GraphQLインターフェイスを定義します。
import { Field, ID, InterfaceType } from '@nestjs/graphql';
@InterfaceType()
export abstract class Character {
@Field((type) => ID)
id: string;
@Field()
name: string;
}
注意
TypeScriptのinterfaceはGraphQLのインターフェイスを定義できません。
これにより、SDLでGraphQLスキーマの以下の部分が生成されます。
interface Character {
id: ID!
name: String!
}
そこから、Characterインターフェイスを実装するにはimplementsキーを使用します。
@ObjectType({
implements: () => [Character],
})
export class Human implements Character {
id: string;
name: string;
}
メモ
@ObjectType()デコレータは、@nestjs/graphqlパッケージからインポートします。
ライブラリが生成するデフォルトのresolveType()関数は、resolverメソッドから返された値に基づいて型を抽出します。つまり、クラスのインスタンスを返す必要があります(リテラルなJavaScriptオブジェクトは返せません)。
カスタマイズしたresolveType()関数を提供するには、以下のように @InterfaceType()デコレーターに渡されるオプション・オブジェクトにresolveTypeプロパティを渡します。
@InterfaceType({
resolveType(book) {
if (book.colors) {
return ColoringBook;
}
return TextBook;
},
})
export abstract class Book {
@Field((type) => ID)
id: string;
@Field()
title: string;
}

インターフェイスのリゾルバ(Resolver)

これまでは、インターフェイスを使うことで、フィールド定義だけをオブジェクトと 共有することができました。もし、実際のフィールドリゾルバの実装も共有したい場合は、以下のように 専用のインターフェイスリゾルバを作成します。
import { Resolver, ResolveField, Parent, Info } from '@nestjs/graphql';
@Resolver(type => Character) // Reminder: Character is an interface
export class CharacterInterfaceResolver {
@ResolveField(() => [Character])
friends(
@Parent() character, // Resolved object that implements Character
@Info() { parentType }, // Type of the object that implements Character
@Args('search', { type: () => String }) searchTerm: string,
) {
// Get character's friends
return [];
}
}
これで、Characterインターフェイスを実装するすべてのオブジェクトタイプに対して、friendsフィールドリゾルバが自動登録されるようになりました。

スキーマファースト

スキーマファーストのアプローチでインターフェイスを定義するには、SDLでGraphQLインターフェイスを作成すれば大丈夫です。
interface Character {
id: ID!
name: String!
}
そして、型付け生成機能を使って対応するTypeScriptの定義を生成できます。
export interface Character {
id: string;
name: string;
}
インターフェイスは、リゾルバマップ中に__resolveType フィールドを追加して、 インターフェイスがどの型に解決すべきかを決定する必要があります。CharactersResolverクラスを作成し、__resolveTypeメソッドを定義しましょう。
@Resolver('Character')
export class CharactersResolver {
@ResolveField()
__resolveType(value) {
if ('age' in value) {
return Person;
}
return null;
}
}
メモ
すべてのデコレータは@nestjs/graphqlパッケージからインポートできます。