Как написать мутацию GraphQL, которая допускает частичные обновления?

#ruby-on-rails #graphql

#ruby-on-rails #graphql

Вопрос:

Итак, я работаю над попыткой изучить GraphQL для ruby для проекта.

Я почти запустил некоторые ее части, но у меня возникли проблемы с другими частями. Существует множество руководств, которые охватывают ультраосновы, но ни одно из них, похоже, не развивается в правильном направлении.

У меня есть мутация для обновления моего пользователя. Пока все хорошо. Я могу искать пользователя по его идентификатору и обновлять одно конкретное поле. Я могу расширить это до обновления двух полей.

Чего я не могу сделать, и это выглядит безумным, так это обобщить эти поля — вообще. К моей пользовательской модели будет прикреплено более 20 полей — номера телефонов, адреса, должность и т.д. и т.п.

Когда я создаю мутацию, я должен определить аргументы, которые входят в метод resolve. Пока все хорошо. Затем я определяю поля, которые может возвращать мутация. Опять же, пока все хорошо.

Затем я перехожу к фактическому методу разрешения.

Исходный синтаксис неплох. def resolve(user_id:, name:, email:) . Затем вы обнаруживаете, что, несмотря на то, что требуется установить значение false, вы должны включить все значения. Вам нужно указать значения по умолчанию для необязательных переменных. Таким образом, это становится def resolve(user_id:, name: null, email: null) — но это фактически обнуляет эти значения, вы не можете выполнять частичные обновления. Что еще хуже, представьте, что у вас есть 20 полей, которые вы должны установить таким образом. Вы можете играть в игры, пытаясь преобразовать аргументы в словарь и отклоняя значения null — но тогда вы не сможете установить свойства равными nil, если им нужно снова быть равными nil.

Ответ №1:

Решение: оператор двойного разделения. Ваш синтаксис становится def resolve(user_id:, **args) . Из того, что я могу сказать, это превращает все оставшиеся именованные аргументы в словарь — и я думаю, что безымянные аргументы станут массивом. Не уверен, как это будет реагировать на сочетание двух.

Полная модель становится:

   argument :user_id, ID, required: true#, loads: Types::UserType
  argument :name, String, required: false
  argument :email, String, required: false

  field :user, Types::UserType, null: true
  field :errors, Types::UserType, null: true

  def resolve(user_id:, **args)
    user = User.find(user_id)
    if user.update(args)
      {
        user: user,
        errors: []
      }
    else
      {
        user: nil,
        errors: user.errors.full_messages
      }
    end
  end
end