GraphQL.js で Custom Scalars を定義する - まずは serialize から
(=˘ ꒳ ˘=) GraphQL.js の TypeScript の定義を眺めながらなんとなくな雰囲気で Custom Scalar を定義してみる
...GraphQL.js の GraphQLScalarType
を使います。コンストラクタの引数は以下のようになっています。
export interface GraphQLScalarTypeConfig<TInternal, TExternal> { name: string; description?: string; astNode?: ScalarTypeDefinitionNode; serialize(value: any): TExternal | null | undefined; parseValue?(value: any): TInternal | null | undefined; parseLiteral?(valueNode: ValueNode): TInternal | null | undefined; }
とりあえず name
と serialize
が最低限必要みたいですね。
シリアライズで何もしない
現在時刻の Unix 秒をソースにして graphql を実行する処理を書いてみましょう。まずはシリアライズで何もしないようにします。
import { graphql, GraphQLScalarType, GraphQLObjectType, GraphQLSchema, } from 'graphql' const GraphQLDate = new GraphQLScalarType({ name: 'Date', serialize(value) { // 何もしない (*˘꒳˘*) ただ返すだけ... return value }, }) const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'rootQuery', fields: { now: { type: GraphQLDate, }, }, }), }) const query = `{ now }` const rootValue = { // 現在時刻をUnix秒で返す now: () => Date.now(), } graphql(schema, query, rootValue).then(console.log, console.error)
これを実行すると
{ data: { now: 1518864848888 } }
と、Unix 秒がそのまま取得されるのがわかります。
シリアライズで変換処理
次にシリアライズを Unix 秒からISOの時刻文字列に変換する処理に変更してみます。
const GraphQLDate = new GraphQLScalarType({ name: 'Date', serialize(value) { // もう何もしないぼくじゃない (*˘꒳˘*) ただ返すだけとか無能 return new Date(value).toISOString() }, })
とすると
{ data: { now: '2018-02-17T10:56:22.882Z' } }
ISOの時刻文字列に変換された値が取得できます。
という感じで GraphQL.js で Custom Scalars を使う方法がなんとなくわかりましたね。
GraphQL で時刻を扱う
GraphQL で時刻を扱う場合、現在メジャーなパッケージは graphql-iso-date になるでしょうか。
参考までに覗いてみると型定義は
src/dateTime/index.js
に存在します。基本的な定義は大体読めるようになりましたが、今回触れなかった parseLiteral
や parseValue
といった定義が serialize
の他にも行われていますね。
また調べていきたいところです。
余談
graphql
を実行している以下の部分
const query = `{ now }` const rootValue = { now: () => Date.now(), } graphql(schema, query, rootValue).then(console.log, console.error)
サンプルコードとしてわかりやすく書きたかったので今回は丁寧に手前で変数を定義して実行していますが、もうすこし簡単に書けてしまいます。
rootValue
の定義をよく見て見ると now
で Date.now
を呼んでいるだけなので Date
をそのまま使っても同様のインタフェースを提供できますね。なので
graphql(schema, `{ now }`, Date).then(console.log, console.error)
のようにワンライナーで実行できてしまいます。