Directive
GraphQLにおけるDirective(ディレクティブ)とは、GraphQLスキーマあるいは操作の一部を追加構成で装飾するものです。GraphQLでは、デフォルトで使えるいくつかのDirectiveが用意されています。
@include(if: Boolean)
:引数がtrue
の場合のみ、このフィールドを結果に含める@skip(if: Boolean)
:引数がtrue
の場合、このフィールドをスキップする@deprecated(reason: String)
:非推奨のフィールドとして、メッセージとともに表示する
Directiveは
@
から始まる識別子で、オプションでその後に名前付き引数のリストを付けられます。Apolloサーバが指令に遭遇したときの動作を指示するために、トランスフォーマ関数を作成できます。この関数は、
mapSchema
関数を使用してスキーマ内の位置(フィールド定義、型定義など)を繰り返し、対応する変換を実行します。import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils';
import { defaultFieldResolver, GraphQLSchema } from 'graphql';
export function upperDirectiveTransformer(
schema: GraphQLSchema,
directiveName: string,
) {
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const upperDirective = getDirective(
schema,
fieldConfig,
directiveName,
)?.[0];
if (upperDirective) {
const { resolve = defaultFieldResolver } = fieldConfig;
// Replace the original resolver with a function that *first* calls
// the original resolver, then converts its result to upper case
fieldConfig.resolve = async function (source, args, context, info) {
const result = await resolve(source, args, context, info);
if (typeof result === 'string') {
return result.toUpperCase();
}
return result;
};
return fieldConfig;
}
},
});
}
ここで、
GraphQLModule#forRoot
メソッド内でtransformSchema
関数を使ってupperDirectiveTransformer
の変換関数を適用します。GraphQLModule.forRoot({
// ...
transformSchema: (schema) => upperDirectiveTransformer(schema, 'upper'),
});
一度登録すれば,
@upper
ディレクティブをスキーマで使用できるようになります.ただし,ディレクティブを適用する方法は,使用するアプローチ(コードファーストかスキーマファーストか)によって異なります。コードファーストのアプローチでは、
@Directive()
デコレータを使ってディレクティブを適用します。@Directive('@upper')
@Field()
title: string;
メモ
@Directive()
デコレータは、@nestjs/graphql
パッケージからインポートできます。ディレクティブは、フィールド、フィールドリゾルバ、入力、オブジェクトタイプ、およびクエリ、ミューテーション、サブスクリプションに適用することができます。以下は、クエリハンドラレベルで適用されたディレクティブの例です。
@Directive('@deprecated(reason: "This query will be removed in the next version")')
@Query(returns => Author, { name: 'author' })
async getAuthor(@Args({ name: 'id', type: () => Int }) id: number) {
return this.authorsService.findOneById(id);
}
注意
@Directive()
デコレータで適用したディレクティブは、生成されたスキーマ定義ファイルには適用されません。最後に、
GraphQLModule
で以下のようにディレクティブを宣言することを確認します。GraphQLModule.forRoot({
// ...,
transformSchema: schema => upperDirectiveTransformer(schema, 'upper'),
buildSchemaOptions: {
directives: [
new GraphQLDirective({
name: 'upper',
locations: [DirectiveLocation.FIELD_DEFINITION],
}),
],
},
}),
メモ
GraphQLDirective
とDirectiveLocation
の両方がgraphql
パッケージからエクスポートされます。スキーマファーストのアプローチでは、SDLで直接ディレクティブを適用します。
directive @upper on FIELD_DEFINITION
type Post {
id: Int!
title: String! @upper
votes: Int
}
Last modified 10mo ago