graphql-rubyでCustom Scalarsを定義してみる
こんにちは!kossyです!
今回はgraphql-rubyでCustom Scalarsを定義する方法について、備忘録としてブログに残してみたいと思います。
環境
Ruby 2.6.8
Rails 6.0.4
MacOS BigSur
graphql-ruby 1.12.19
CustomScalarsとは
graphqlにはデフォルトで組み込まれているいくつかのscalar値があります。
String, like a JSON or Ruby string
Int, like a JSON or Ruby integer
Float, like a JSON or Ruby floating point decimal
Boolean, like a JSON or Ruby boolean (true or false)
ID, which a specialized String for representing unique object identifiers
ISO8601DateTime, an ISO 8601-encoded datetime
ISO8601Date, an ISO 8601-encoded date
JSON, ⚠ This returns arbitrary JSON (Ruby hashes, arrays, strings, integers, floats, booleans and nils). Take care: by using this type, you completely lose all GraphQL type safety. Consider building object types for your data instead.
BigInt, a numeric value which may exceed the size of a 32-bit integer
上記以外でも、scalarsを開発者が独自に定義することができます。それがCustomScalarsです。
CustomScalarsの定義
CustomScalarsを定義するには、Types::BaseScalarを継承したクラスを作成する必要があります。
module Types class PhoneNumber < Types::BaseScalar description 'PhoneNumber' def self.coerce_input(input_value, _context) if input_value.match?(/\A\d{10,11}\z/) input_value else raise GraphQL::CoercionError, "#{input_value.inspect} is not a valid Phone Number." end end def self.coerce_result(ruby_value, context) ruby_value.to_s end end end
このように定義を行い、
module Types class UserInfoInputType < Types::BaseInputObject argument :phone_number, Types::PhoneNumber, required: true end end
のようにargument等で指定することによって適用することができます。
graphiql等のGrapQL Clientで試した結果は以下です。
{ "errors": [ { "message": "Variable $userInfoInput of type UserInfoInputForm! was provided invalid value for userInfo.phoneNumber (\"タイトル\" is not a valid Phone Number.)", "locations": [ { "line": 1, "column": 39 } ], "extensions": { "value": { "userInfo": { "phoneNumber": "タイトル" } }, "problems": [ { "path": [ "userInfo", ], "explanation": "\"タイトル\" is not a valid Phone Number.", "message": "\"タイトル\" is not a valid Phone Number." } ] } } ] }
「タイトル」という文字列はInvaildだという例外が得られました。
正しい文字をargumentとして渡した場合を見てみます。
{ "data": { "updateUserInfo": { "userInfo": { "phoneNumber": "09012345678" } } } }
例外が起こらずに処理が完了しました。
まとめ
CustomScalarを使えば、プリミティブな型(StringやInt等)を使うよりもより厳密にデータを扱うことができそうです。