簡體   English   中英

GraphQL Ruby:如何編寫具有多個參數的 DRY 突變?

[英]GraphQL Ruby: How to write DRY mutations with multiple parameters?

我正在使用 app 為我的graphql-ruby編寫一個基於devise- jwt的身份驗證系統。 在這個過程中,我為創建一個新的用戶帳戶做了一個改變,它需要 7 個參數,這在我的代碼中產生了很多重復:

module Mutations
  class SignUpMutation < Mutations::BaseMutation
    argument :email, String, required: true
    argument :password, String, required: true
    argument :family_name, String, required: true
    argument :family_name_phonetic, String, required: true
    argument :given_name, String, required: true
    argument :given_name_phonetic, String, required: true
    argument :newsletter_optin, Boolean, required: false

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

    def resolve(email:, password:,
                family_name:, family_name_phonetic:,
                given_name:, given_name_phonetic:,
                newsletter_optin:
               )
      result = {
        token: nil,
        user: nil
      }
      new_user = User.new(
        email: email,
        password: password,
        family_name: family_name,
        family_name_phonetic: family_name_phonetic,
        given_name: given_name,
        given_name_phonetic: given_name_phonetic,
        newsletter_optin: newsletter_optin
      )
      if new_user.save!
        result[:token] = new_user.token
        result[:user] = new_user
      end
      result
    end
  end
end

我怎么能干掉這個以避免在所有地方重復突變參數的名稱?

先感謝您!

回答我自己的問題。 不必處理這么多參數的正確方法是使用輸入對象而不是單獨的參數。 來自graphql-ruby 文檔

輸入對象類型是 GraphQL 操作的復雜輸入。 它們非常適合需要大量結構化輸入的字段,例如突變或搜索字段。

所以我已經定義了我的輸入對象:

module Types
  class UserAttributes < Types::BaseInputObject
    description 'Attributes for creating or updating a user'
    argument :email, String, required: true
    argument :password, String, required: true
    argument :family_name, String, required: true
    argument :family_name_phonetic, String, required: true
    argument :given_name, String, required: true
    argument :given_name_phonetic, String, required: true
    argument :newsletter_optin, Boolean, required: false
  end
end

然后像這樣重構我的突變:

module Mutations
  class SignUpMutation < Mutations::BaseMutation
    argument :attributes, Types::UserAttributes, required: true

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

    def resolve(attributes:)
      result = {
        token: nil,
        user: nil
      }
      new_user = User.new(attributes.to_hash)
      if new_user.save!
        result[:token] = new_user.token
        result[:user] = new_user
      end
      result
    end
  end
end

最后,這段代碼感覺更像 ruby​​ :)

如果你願意,你可以做這樣的事情:

[
  :email,
  :password,
  :family_name,
  :family_name_phonetic,
  :given_name,
  :given_name_phonetic
].each do |arg|
  argument arg, String, required: true
end

您可能認為除此之外再多也不為過,但 Ruby非常靈活。 如果你真的想,你甚至可以做類似的事情

def resolve(email:, password:,
            family_name:, family_name_phonetic:,
            given_name:, given_name_phonetic:,
            newsletter_optin:)
  result = {
    token: nil,
    user: nil
  }
  params = method(__method__).parameters.map(&:last)
  opts = params.map{|p| [p, eval(p.to_s)]}.to_h
  new_user = User.new(opts)
  if new_user.save!
    result[:token] = new_user.token
    result[:user] = new_user
  end
  result
end

您可以查看此答案以獲取解釋

如果您想要更多,您可以使用更詳細的字段列表和define_method - 您可以一直得到它,直到您只輸入一次,例如:email

那會更好嗎? 也許,如果你有數百個這樣的事情要做。 或者,如果您想在運行時開始定​​義事物。

您可以嘗試使用 double splat (**) 運算符。

module Mutations
  class SignUpMutation < Mutations::BaseMutation
    argument :email, String, required: true
    argument :password, String, required: true
    argument :family_name, String, required: true
    argument :family_name_phonetic, String, required: true
    argument :given_name, String, required: true
    argument :given_name_phonetic, String, required: true
    argument :newsletter_optin, Boolean, required: false

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

    def resolve(**arguments)
      result = {
        token: nil,
        user: nil
      }

      new_user = User.new(
        email: arguments[:email],
        password: arguments[:password],
        family_name: arguments[:family_name],
        family_name_phonetic: arguments[:family_name_phonetic],
        given_name: arguments[:given_name],
        given_name_phonetic: arguments[:given_name_phonetic],
        newsletter_optin: arguments[:newsletter_optin]
      )

      if new_user.save!
        result[:token] = new_user.token
        result[:user] = new_user
      end

      result
    end
  end
end

當然,像您一樣創建一個新類型會更整潔。 但在某些情況下,您可以將它們組合在一起,例如

module Mutations
  class SignUpMutation < Mutations::BaseMutation
    argument :another_attribute, String, required: true
    argument :attributes, Types::UserAttributes, required: true

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

    def resolve(**arguments)
      result = {
        token: nil,
        user: nil
      }

      # use arguments[:another_attribute] for something else.

      new_user = User.new(arguments[:attributes].to_hash)

      if new_user.save!
        result[:token] = new_user.token
        result[:user] = new_user
      end

      result
    end
  end
end

在您的情況下,我也會使用輸入對象,但是如果您有一個現有 API 且客戶端依賴於模式,並且您想“干燥”那些在不同突變/字段中完全相同的重復參數,您會怎么做?

如果您繼續實現一個新的輸入對象,您將更改架構並且客戶端很可能會中斷。 我想在將現有參數移動到輸入對象中時沒有辦法保持模式相同,對嗎?

在不干擾現有 GraphQL 模式的情況下,更好的方法是使用所有常見參數定義 InputType,例如:

module Types
    module Inputs
        class CommonInputType < Types::Root::BaseInputObject
            graphql_name("my_common_input_type")

            argument :email, String, required: true
            argument :newsletter_optin, Boolean, required: true
            ...
            argument :posts, [Types::Inputs::Post], required: true
        end
    end
end

&在一些帶有附加參數的突變中使用它,例如:

module Mutations
    class CreateUser < Mutations::BaseMutation

        argument :additional_arg_one, ID, required: true
        argument :additional_arg_two, String, required: false
        ...

        Types::Inputs::CommonInputType.arguments.each do |arg,properties|
          argument arg.to_sym, properties.graphql_definition.type
        end

    end
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM