Scalar
GraphQLのオブジェクトタイプは名前とフィールドをそれぞれ持ちますが、ある時点でこれらのフィールドは具体的なデータ型で表示される必要があります。そこで登場するのがScalarです。
GraphQLには以下のようなデフォルトの型があります。
Int
、Float
、String
、Boolean
、ID
の5つの型があります。これらの組み込み型に加えて、カスタムのデータ型をサポートしています。コードファーストのアプローチでは、5つのScalarが同梱されており、そのうち3つは既存のGraphQL型の単純なエイリアスになっています。
ID
:一意の識別子を表し、しばしばオブジェクトの再取得やキャッシュのキーとして使われる。Int
:符号付きの32ビット整数。Float
:符号付きの倍精度浮動小数点値。GraphQLISODateTime
:UTCでの日付時間文字列。(デフォルトでDate
型を表現するのに使われる)GraphQLTimeStamp
:日付と時刻をUNIXエポックの開始からのミリ秒数で表現する符号付き整数。
GraphQLISODateTime
(例:2019-12-03T09:54:33Z
)は、デフォルトでDate
型を表すのに使用されます。代わりに GraphQLTimestamp
を使用するには、次のように buildSchemaOptions
オブジェクトのdateScalarMode
を 'timestamp'
に設定します。GraphQLModule.forRoot({
buildSchemaOptions: {
dateScalarMode: 'timestamp',
}
}),
同様に、
GraphQLFloat
はデフォルトで数値型を表現するために使用されます。代わりにGraphQLInt
を使用するには、次のようにbuildSchemaOptions
オブジェクトのnumberScalarMode
を'integer'
に設定します。GraphQLModule.forRoot({
buildSchemaOptions: {
numberScalarMode: 'integer',
}
}),
加えて、カスタムのScalarを作成できます。
Date
スカラーのカスタム実装を作成するには、単に新しいクラスを作成します。import { Scalar, CustomScalar } from '@nestjs/graphql';
import { Kind, ValueNode } from 'graphql';
@Scalar('Date', (type) => Date)
export class DateScalar implements CustomScalar<number, Date> {
description = 'Date custom scalar type';
parseValue(value: number): Date {
return new Date(value); // value from the client
}
serialize(value: Date): number {
return value.getTime(); // value sent to the client
}
parseLiteral(ast: ValueNode): Date {
if (ast.kind === Kind.INT) {
return new Date(ast.value);
}
return null;
}
}
この状態で、
DateScalar
をプロバイダとして登録します。@Module({
providers: [DateScalar],
})
export class CommonModule {}
これで、クラスの中で
Date
型を使えるようになりました。@Field()
creationDate: Date;
カスタムスカラーを使うには、インポートしてリゾルバとして登録します。ここでは、デモ用に
graphql-type-json
パッケージを使用することにします。このnpmパッケージは、JSON
のGraphQLスカラータイプを定義します。まず、このパッケージをインストールすることから始めましょう。
npm i --save graphql-type-json
パッケージがインストールされたら、forRoot()メソッドにカスタムリゾルバを渡します。
import GraphQLJSON from 'graphql-type-json';
@Module({
imports: [
GraphQLModule.forRoot({
resolvers: { JSON: GraphQLJSON },
}),
],
})
export class AppModule {}
これで、
JSON
型をクラスで使えるようになりました。@Field((type) => GraphQLJSON)
info: JSON;
カスタムのスカラーを定義するには、新しい
GraphQLScalarType
インスタンスを作成します。ここでは、カスタムUUID
スカラーを作成します。const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
function validate(uuid: unknown): string | never {
if (typeof uuid !== "string" || !regex.test(uuid)) {
throw new Error("invalid uuid");
}
return uuid;
}
export const CustomUuidScalar = new GraphQLScalarType({
name: 'UUID',
description: 'A simple UUID parser',
serialize: (value) => validate(value),
parseValue: (value) => validate(value),
parseLiteral: (ast) => validate(ast.value)
})
forRoot()
にカスタムリゾルバを渡します。@Module({
imports: [
GraphQLModule.forRoot({
resolvers: { UUID: CustomUuidScalar },
}),
],
})
export class AppModule {}
これで、クラス経由でUUID型を使えるようになりました。
@Field((type) => CustomUuidScalar)
uuid: string;
カスタムのスカラーを定義するには、型定義と専用のリゾルバを作成します。ここでは、公式ドキュメントと同様にデモ用に
graphql-type-json
パッケージを使用することにします。このnpmパッケージは
JSON
のGraphQL
スカラー型を定義します。まずはこのパッケージをインストールしましょう。$ npm i --save graphql-type-json
パッケージがインストールされたら、
forRoot()
メソッドにカスタムリゾルバを渡します。import GraphQLJSON from 'graphql-type-json';
@Module({
imports: [
GraphQLModule.forRoot({
typePaths: ['./**/*.graphql'],
resolvers: { JSON: GraphQLJSON },
}),
],
})
export class AppModule {}
これで、JSONスカラーを型定義で使えるようになりました。
scalar JSON
type Foo {
field: JSON
}
スカラー型を定義するもう一つの方法は、単純なクラスを作成することです。
Date
型でスキーマを拡張する場合を考えてみましょう。import { Scalar, CustomScalar } from '@nestjs/graphql';
import { Kind, ValueNode } from 'graphql';
@Scalar('Date')
export class DateScalar implements CustomScalar<number, Date> {
description = 'Date custom scalar type';
parseValue(value: number): Date {
return new Date(value); // value from the client
}
serialize(value: Date): number {
return value.getTime(); // value sent to the client
}
parseLiteral(ast: ValueNode): Date {
if (ast.kind === Kind.INT) {
return new Date(ast.value);
}
return null;
}
}
この状態で、
DateScalar
をプロバイダとして登録します。@Module({
providers: [DateScalar],
})
export class CommonModule {}
これで、
Date
スカラーを型定義に使えるようになりました。scalar Date
デフォルトでは、すべてのスカラーに対して生成されるTypeScriptの定義はanyであり、特にタイプセーフというわけでもありません。ところが、型の生成方法を指定することでNestがカスタムスカラーの型付けをどのように生成するかを設定できます。
import { GraphQLDefinitionsFactory } from '@nestjs/graphql';
import { join } from 'path';
const definitionsFactory = new GraphQLDefinitionsFactory();
definitionsFactory.generate({
typePaths: ['./src/**/*.graphql'],
path: join(process.cwd(), 'src/graphql.ts'),
outputAs: 'class',
defaultScalarType: 'unknown',
customScalarTypeMapping: {
DateTime: 'Date',
BigNumber: '_BigNumber',
},
additionalHeader: "import _BigNumber from 'bignumber.js'",
});
メモ
また、代わりに型参照を使うこともできます。
DateTime:Date.Name
のように型参照を使うこともできます。この場合、GraphQLDefinitionsFactory
は指定された型のname
プロパティ(Date.name
)を抽出して TS 定義を生成します。注:ビルトインでない型(カスタム型)については、import
文の追加が必要です。さて、以下のようなGraphQLのカスタムスカラー型が与えられたと仮定しましょう。
scalar DateTime
scalar BigNumber
scalar Payload
これで、
src/graphql.ts
に以下のようなTypeScriptの定義が生成されたことが確認できます。import _BigNumber from 'bignumber.js';
export type DateTime = Date;
export type BigNumber = _BigNumber;
export type Payload = unknown;
ここでは、
customScalarTypeMapping
プロパティを使用して、カスタム・スカラー用に宣言したい型のマップを提供します。また、additionalHeader
プロパティも用意し、これらのタイプ定義に必要なインポートを追加できるようにした。最後に、defaultScalarType
に'unknown'
を追加し、customScalarTypeMapping
で指定されていないカスタムスカラーはany
の代わりにunknown
にエイリアスされるようにした(TypeScript では ver3.0 から型の安全性を高めるためにこの使用が推奨されています)。メモ
Last modified 10mo ago