🐥

GraphQL Rubyにおけるmutationのひと工夫

2023/04/02に公開

はじめに

GraphQL Rubyにおいて、rails generate graphql:installを実行して、生成されるBaseMutationはGraphQL::Schema::RelayClassicMutationのサブクラスです。
そして、このクラスでは、argumentを定義すると、まとめられたinputが自動生成されます。
ただ、moduleを切ったときには、ひと工夫が必要になります。

Inputの自動生成

例えば、Userを作成するMutationを以下のようにします。

mutations/user_create.rb
module Mutations
  class UserCreate < BaseMutation
    field :user, Types::Objects::UserType, null: false

    argument :email, String
    argument :password, String
    argument :first_name, String
    argument :last_name, String

    def resolve(**args)
    end
  end
end

生成されるInputをこのようになります。

schema.graphql
"""
Autogenerated input type of UserCreate
"""
input UserCreateInput {
  """
  A unique identifier for the client performing the mutation.
  """
  clientMutationId: String
  email: String!
  firstName: String!
  lastName: String!
  password: String!
}

名前空間を分けることによる問題

ファイル数が増えてくると、見通しが悪くなるので、ディレクトリを分けたくなります。
ただ、単純にmoduleをきるだけでは生成されるInputは意図したものにはなりません。

mutations/users/create.rb
module Mutations
+  module Users
+    class Create < BaseMutation
    end
  end
end

この場合、生成されるInputをこのようになります。

schema.graphql
"""
Autogenerated input type of Create
"""
input CreateInput {
  """
  A unique identifier for the client performing the mutation.
  """
  clientMutationId: String
  email: String!
  firstName: String!
  lastName: String!
  password: String!
}

CreateInputというシンプルな名前になってしまいました。
これだと、ほかにもCreateクラスが合った場合に自動生成されると上書きされてしまうという問題があります。

解決策

上記の問題を解決するのは、たった一行追加するだけです。
それは graphql_name です。

mutations/users/create.rb
module Mutations
  module Users
    class Create < BaseMutation
+      graphql_name('UserCreate')

これで生成されるInputは最初のものと同じになります。

schema.graphql
"""
Autogenerated input type of UserCreate
"""
input UserCreateInput {
  """
  A unique identifier for the client performing the mutation.
  """
  clientMutationId: String
  email: String!
  firstName: String!
  lastName: String!
  password: String!
}

GraphQL Rubyのコードでいうとこの部分になります。
https://github.com/rmosolgo/graphql-ruby/blob/master/lib/graphql/schema/relay_classic_mutation.rb#L153

Addition

moduleから命名をいい感じにするクラスメソッドを一つBaseクラスに作ると便利です。

mutations/base_mutation.rb
module Mutations
  class BaseMutation < GraphQL::Schema::RelayClassicMutation
    # ex) Mutations::Users::CreateをUserCreateにする
    def self.build_graphql_name
      name.split('::').drop(1).map(&:singularize).join('')
    end
  end
end
mutations/users/create.rb
module Mutations
  module Users
    class Create < BaseMutation
+      graphql_name(build_graphql_name) # UserCreate 

Discussion