19
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GraphQLのmutationでargumentにオブジェクトを渡す

Last updated at Posted at 2019-12-01

graphql-ruby で Mutation を書いていて、 argument にスカラ型ではなくオブジェクトを渡す時に variables を併用する場合の書き方で詰まったのでメモを残しておく。

環境

  • Rails 6.0.0
  • graphql-ruby 1.9.14

目標

  • createUser という mutation の argument にオブジェクトを渡す
  • クライアント側のクエリでは variables を用いる

手順

MutationType にフィールドを追加する

app/graphql/types/mutation_type.rb
module Types
  class MutationType < Types::BaseObject
    field :createUser, mutation: Mutations::CreateUserMutation
  end
end
  • mutation_type.rb に createUser というフィールドを追加し、 Mutations::CreateUserMutation を紐付ける

CreateUserMutation を実装する

app/graphql/mutations/create_user_mutation.rb
module Mutations
  class CreateUserMutation < GraphQL::Schema::RelayClassicMutation
    graphql_name "CreateUser"

    field :user, Types::UserType, null: true
    field :error, String, null: true

    argument :user, Types::Attributes::UserInput, required: true

    def resolve(user:)
      created_user = User.create(user.to_h.indifferent_access.transform_keys(&:underscore))

      { user: created_user }
    rescue ActiveRecord::RecordInvalid => error
      { error: error.message }
    end
  end
end
  • field :user は、この mutation 実行後のレスポンスとして取得できるフィールド。
  • Types::UserType は普段 query で使用する BaseObject なので内容は割愛。
  • argument :user が本題。 user というリクエストパラメータを受け取ることを宣言。そのオブジェクトの方を Types::Attributes::UserInput というクラスで定義している(詳細は後述)。
  • 上記で宣言したリクエストパラメータを resolve メソッドのキーワード引数で受け取る。

ちなみに user の中身はハッシュではなく Types::Attributes::UserInput のインスタンスになっている。
そのため中のプロパティにアクセスするには下記の二通りある。

user.postal_code # インスタンスメソッドを通してアクセス
user[:postalCode] # ハッシュのキーを通してアクセス(この時、プロパティ名はキャメルケースにする)

単純に to_h するだけだとキーがキャメルケースのままなので、 with_indifferent_access.transform_keys(&:underscore) という長ったらしい変換処理が必要になる。
当然、他の mutation 内でも使うことが予想されるので、 Types::BaseInputObject クラス内にインスタンスメソッドを定義してしまうと良いと思う。

app/graphql/types/base_input_object.rb
module Types
  class BaseInputObject < GraphQL::Schema::InputObject
    argument_class Types::BaseArgument

    def to_params
      to_h.with_indifferent_access.transform_keys(&:underscore)
    end
  end
end

これなら user.to_h.indifferent_access.transform_keys(&:underscore)user.to_params に置き換えられる。

Types::Attributes::UserInput を実装する

app/graphql/types/attributes/user_input.rb
class Types::Attributes::UserInput < Types::BaseInputObject
  argument :name, String, required: true
  argument :gender, Integer, required: true
  argument :profile, String, required: true
  argument :postal_code, String, required: true
end
  • 先述した resolve メソッドで受け取るキーワード引数の型を下記のように定義する。型の書き方などは query_types 等と同様。
  • さらにオブジェクトをネストしたい時は Types::BaseInputObject を継承する別のクラスを指定するのかな?(試してない)

以上でサーバー側の実装は完了。

クライアント側から送信する query を書く

mutation registerUser(
  $user: UserInput!
) {
  createUser(input: { user: $user }) {
    user { id postalCode profile }
  }
}
  • 1行目の registerUser はこのクエリに付けた適当な名前なので変えても動く。
  • 2行目の UserInput!! がキモ。 Mutations::CreateUserMutationargumentrequired: true を指定した場合、この ! を付けないと Nullability mismatch on variable $user というエラーが出る(ここで1時間くらいハマった)。
  • 4行目の createUser が Types::MutationType で定義した mutation 名。
  • 5行目の user { id postalCode profile } が mutation 実行後のレスポンスボディに入れてほしいオブジェクトとフィールドの指定。

クエリを実行

query = <<-QUERY
  mutation registerUser(
    $user: UserInput!
  ) {
    createUser(input: { user: $user }) {
      user { id postalCode profile }
    }
  }
QUERY
variables = {
  karte: {
    name: "midwhite",
    gender: 1,
    profile: "I am a software engineer."
    postalCode: "000-0000"
  }
}
AppSchema.execute(query, variables: variables).to_h
  • variables に user オブジェクトとして渡したいパラメータをハッシュで記述する。

実際にはフロントから Apollo とか使って query や variables を送信するんだと思うけど、 query の形式さえ分かっていれば特に迷わないだろうと思うのでその部分は割愛。
ここまで分かれば mutation を実用レベルで書けそう。そろそろエンドポイントを GraphQL のみで実装したアプリケーションを書いてみたい気持ち。

19
10
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
19
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?