LoginSignup
3
1

【GraphQL Ruby】値が空文字の場合に null が返るように

Last updated at Posted at 2024-02-25

結論

class NilIfEmpty < GraphQL::Schema::FieldExtension
  def after_resolve(value:, **_rest)
    value.presence
  end
end
class Types::BaseField < GraphQL::Schema::Field
  def initialize(*args, **kwargs, &block)
    super
    # NOTE: unwrap を使うと、String! のような null: false のフィールドでも if の中を通せる
    if type.unwrap == GraphQL::Types::String
      extension(NilIfEmpty)
    end
  end
end

背景など

Rails × GraphQL Ruby で GraphQL サーバーを実装していて、非必須な String 型のデータのためにDBレベルでカラムに空文字のデフォルト設定がついている場合、GraphQL のレイヤーで null: true としていても、値がない場合でも空文字が返ってしまいます。

クライアント側としては、型のある言語を採用している場合などは特に、非必須な String フィールドの値は「null でも空文字でもない値 or null」の形になっていると扱いやすいため、値がない場合には必ず null が返るようにしたいと考えました。

これを実現するため、DBレベルでデフォルト値の設定をしない、という方法があると思いますが、非必須なカラムで nil(null)
と空文字の両方を考慮する必要が出てくる、などの理由で、安易に踏み込めないのかなと思います(管理画面などの実装も同じ Rails アプリケーションで実現している場合などは特に...)

GraphQL のレベルで解決するとして、フィールドと同名のメソッドを定義し、object.xxxxx.presence みたいな処理を書けば一応実現はできます。ただ、すべての String 型フィールドでこのメソッドを定義するのは苦しいです。

そこで、上記コードのように Field Extensions と GraphQL::Schema::FieldExtension#after_resolve を使い、GraphQL::Types::String の場合は必ず .presence を通った値が返されるようにするのがよさそうに思いました。

補足

もし、空文字と null を区別したいフィールドが一部存在する場合は、そのフィールドだけでこの Extension を適用しないオプションを設定するのかなと思います。こちらは未検証ですが、ドキュメントを読む限りは、以下のように書くことができそうです。

# ドキュメントからそのまま引用しています↓

class Types::BaseField < GraphQL::Schema::Field
  # @param custom_extension [Boolean] if false, `MyCustomExtension` won't be added
  # @example skipping `MyCustomExtension`
  #   field :no_extension, String, custom_extension: false
  def initialize(*args, custom_extension: true, **kwargs, &block)
    super(*args, **kwargs, &block)
    # Don't apply this extension if the field is configured with `custom_extension: false`:
    if custom_extension
      extension(MyCustomExtensions)
    end
  end
end

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1