GraphQLでDateTimeを扱う時、フォーマットを指定する。

GraphQLにはScalarTypeというクラスが存在する。

ScalarTypeは配列やオブジェクト(いわゆるkey-valueペア)、enumではないタイプの基底クラスになる。

GraphQLではこのScalarTypeをベースとした5つの基本タイプが仕様として定義されている。

  • Int - 符号付き32ビット整数
  • Float - 倍精度少数
  • String - UTF-8文字シーケンス
  • Boolean - true or false
  • ID - GUID

これだけだとDateTime等で困るので、DateTimeのGraphQLTypeを作ってみる。

date_time_type.rb

graphql-rubyを使う

https://github.com/rmosolgo/graphql-ruby

DateTimeType = GraphQL::ScalarType.define do
  name 'DateTimeType'
  description 'ActiveRecord::Type::DateTimeに対応したType'

end

このままだとクエリに対する出力結果が

{
  "data": {
    "series": {
      "created_at": "2017-01-09T18:55:30.000Z"
    }
  }
}

になる。せっかくGraphQLなので、フォーマットもクエリとして与えられるようにしたい。

created_atフィールドをいじる

普通にcreated_atを一属性として扱うだけなら

field :title, DateTimeType

の記述だけで済むが、今回は引数formatを与えると、その通りに整形してくれるようにする。

  field :created_at do
    type DateTimeType
    argument :format, types.String
    resolve ->(obj, args, ctx) {
      return obj.created_at if args[:format].nil?

      obj.created_at.strftime(args[:format])
    }
  end

これでqueryを叩く

{
  series(id: 3) {
    created_at(format:"%Y年%m月%d日 %H:%M:%S")
  }
}

{
  "data": {
    "series": {
      "created_at": "2017年01月09日 18:55:30"
    }
  }
}

良い。 本当はフォーマットの仕組みをTypeそのものに持たせたいのだけれど、TypeのresultがStringを取ることになるので適切では無さそう。