概要
Goで実装しているGraphQLサーバーがあって、そのQueryの引数にInt型とBool型を要求していて、それぞれ "1000" と "true" といった値を渡したときに、Intは正しく動いて、Boolは message: "cannot use string as Boolean"
というエラーメッセージが返ってきた。
この違いは正しいのか?意図されている動きなのか?どこが原因なのか?を探った記事です。
環境
バージョン | |
---|---|
Go | 1.13.7 |
gqlgen | 0.10.2 |
Intの引数にString型を与えてもうまく変換されていることの調査
gqlgenで生成されるgenerated.go
から、ライブラリのソースコードをたどっていくとここへ行き着いた
UnmarshalInt関数の中で以下のように変換している。なるほど。
return strconv.Atoi(v)
意図してStringをIntに変換しているんですね。
BoolにString型を与えてもうまく動かないことの調査
エラーメッセージはmessage: "cannot use string as Boolean"
だったのだが、まず気になったのはそもそも👆でintは変換しているので、boolでも同じようなメソッドがないかと思って調べてみた。そしたらあった!
return strings.ToLower(v) == "true", nil
ガッツリ変換してた笑
で、デバッグ止めようと思ってもここまでたどり着いてなかったんですよね。で、
このあたり👆にブレークポイント置いて調査してみたところ、、、見つけた!
gqlgenが依存している、gqlparserというライブラリの中でIntはStringを許可しているのに、BoolはStringを許可していませんでした。そして最初に見たエラーメッセージが生成されているのも確認できました。
この動作で正しいのだろうか?
と思ったので仕様書を見てみました。
Int
Input Coercion When expected as an input type, only integer input values are accepted. All other input values, including strings with numeric content, must raise a query error indicating an incorrect type. If the integer input value represents a value less than -231 or greater than or equal to 231, a query error should be raised.
Note: Numeric integer values larger than 32‐bit should either use String or a custom‐defined Scalar type, as not all platforms and transports support encoding integer numbers larger than 32‐bit.
数値を表す奴は数値型じゃないとエラーを出さなきゃダメ、Stringもエラー。 ・・・でも、全ての環境で32bit Intより大きい値を扱えるわけじゃないし、そういうデカい値扱うときは一旦Stringでも良い。
って感じでしょうか。なので、一旦Stringで受け取って、32bitより大きい値だったらエラーにする、という実装も許しているようです。
Bool
Input Coercion
When expected as an input type, only boolean input values are accepted. All other input values must raise a query error indicating an incorrect type.
Booleanしかダメ!という方針みたいです。
ということで、IntとBoolの動作の違いは仕様書通りの作りになっていると言えそうです。
なるほどなぁ〜
補足
- 読む仕様書が違う
- 読む部分が違う
とかあったら優しく教えていただけると幸いです🙇