GraphQLで独自Scalar型を定義する時に気をつけること
GraphQL-Rubyでは、Int
、Float
、String
、Boolean
,ID
といったビルドイン以外にISO8601DateTime
やISO8601Date
型が提供されています。
また、独自Scalar型を定義することができ、その方法はドキュメントに記載されています。
class Types::Url < Types::BaseScalar def self.coerce_input(input_value, context) url = URI.parse(input_value) if url.is_a?(URI::HTTP) || url.is_a?(URI::HTTPS) url else raise GraphQL::CoercionError, "#{input_value.inspect} is not a valid URL" end end def self.coerce_result(ruby_value, context) ruby_value.to_s end end
上記のように独自Scalar型を定義できますが、graphql-specから一点忘れてはいけないことがあります。
それは、InputとResultでバリデーションを行い適切なエラーを出す必要があるということです。
Types::Url
では、self.coerce_input
メソッドでGraphQL::CoercionError
を出力していることがわかります。
また、Resultではruby_value.to_s
とあり一見するとエラーを出していないように思われます。to_s
メソッドは、ほぼ全てRubyオブジェクトに適応できてしまうため結果がIntegerであるパターンを考えます。
シンプルな独自ScalerであるBigInt
がGraphQL-Rubyに実装されています。もし、Arrayが与えられた時、value.to_i
を実行するとNoMethodError
が出力されます。rescue
などで拾ってやる必要はありそうですが、Resultでもバリデーションをチェックすることが必要であるとわかります。
lib/graphql/types/big_int.rb # frozen_string_literal: true module GraphQL module Types class BigInt < GraphQL::Schema::Scalar description "Represents non-fractional signed whole numeric values. Since the value may exceed the size of a 32-bit integer, it's encoded as a string." def self.coerce_input(value, _ctx) Integer(value) rescue ArgumentError nil end def self.coerce_result(value, _ctx) value.to_i.to_s end end end end
まとめ
GraphQLで独自Scalerを定義する際は、バリデーションをしてエラーを出すべきだ
初めてのGraphQL ―Webサービスを作って学ぶ新世代API
- 作者:Eve Porcello,Alex Banks
- 出版社/メーカー: オライリージャパン
- 発売日: 2019/11/13
- メディア: 単行本(ソフトカバー)