GraphQLのfieldに付くresolveをTypeによって指定する。
GraphQLでDateTimeを扱う時、フォーマットを指定する。 - あのにのに
前回の記事で 「DateTime型とかはクエリ側で出力フォーマットを引数として指定できると便利!」 って話をしました。
ついでに課題として
DateTimeTypeって作ったけど意味なくない..?
いちいちresolveにフォーマット付与を記述するの面倒じゃない?
という物があったのでこれを解決したいと思います。
やること
Typeが**ならresolveでxxをする。と言うような仕組みを作ります。
今回の場合だと 「fieldのTypeがDateTimeTypeの場合、そのfieldに引数[:format]を用意し、resolveではformatに応じで出力フォーマット通りに書こうするようにする。」 になります。
これができるようになると、DateTimeTypeが付いたfieldは全て[:format]が使えるようになります。
ちなみに使用するgemは前回に引き続き
https://github.com/rmosolgo/graphql-ruby
です。
やってく
今回はGraphQL::Define::AssignObjectFieldをモンキーパッチをあてる形で動かしてみます。 GraphQL::Define::AssignObjectField#callの程よくfieldが得られたタイミングで
if field.type.to_s == 'DateTime' field.arguments['format'] = GraphQL::Argument.define(name: 'format', type: -> { GraphQL::STRING_TYPE }) end
ついた!
次にリゾルバを作ります。
class DateTimeTypeFormatResolver def initialize(attr_name) @attr_name = attr_name end def call(obj, args, ctx) return obj[@attr_name].strftime(args[:format]) if args[:format].present? obj[@attr_name] end end
こんな感じ。あとは
if field.type.to_s == 'DateTime' field.arguments['format'] = GraphQL::Argument.define(name: 'format', type: -> { GraphQL::STRING_TYPE }) field.resolve=(DateTimeTypeFormatResolver.new(name)) end
とか書けばok
一応これで完成。
割りと便利な気がする。
今回新たにうまれた課題としては
- 他でリゾルバを記述したくなったらどうするんだ
- この書き方だとModelの属性名とTypeのfield名が一致している場合しかつかえない
次↑について考えます。
あとはその他便利拡張あればやる。