iT邦幫忙

2021 iThome 鐵人賽

DAY 30
0
自我挑戰組

冒險村-30 Day Ruby on Rails Tips Challenge系列 第 30

冒險村30 - Handle API response with value objects

30 - Handle API response with value objects

本篇將介紹撰寫 Rails 的過程中整個重構的過程,比較偏向一個方向,以一個簡單的例子為例,假設我們請求 API 獲取 Active 的 User 列表:

以下的程式是一個很常見的方法,但這段程式碼中,不只打 Api + parser + 過濾 active user,這樣的方式並沒有辦法讓程式碼只負責一件事情。

  response = Request.call('some_url')
  parsed_response = JSON.parse(response)

  eligible_users = []

  parsed_response['people'].each do |person|
    if person['active'] == true
      eligible_users << {
        name: "#{person['firstName']} #{person['lastName']}",
        email: person['emailAddress']
      }
    end
  end

  eligible_users

The parser for the people

Parser 的責任在負責接收並提供方法來 return User

  response = Request.call('some_url')
  parser = PeopleParser.new(response)

  eligible_users = []

  parser.people.each do |person|
    if person['active'] == true
      eligible_users << {
        name: "#{person['firstName']} #{person['lastName']}",
        email: person['emailAddress']
      }
    end
  end

  eligible_users

Value object for a person

我們需要一個 pure ruby object 來處理 person

  class Person
    def initialize(attributes)
      @attributes = attributes
    end

    def active?
      @attributes['active']
    end

    def email
      @attributes['emailAddress']
    end

    def name
      "#{@attributes['firstName']} #{@attributes['lastName']}"
    end
  end

有了上述的 Person Object 我們的 Parser 可以再來進行修改

  class PeopleParser
    def initialize(raw_response)
      @raw_response = raw_response
    end

    def people
      @parsed_json['people'].map { |attributes| Person.new(attributes) }
    end

    private

    def parsed_json
      @parsed_json ||= JSON.parse(@raw_response)
    end
  end
  response = Request.call('some_url')
  parser = PeopleParser.new(response)

  eligible_users = []

  parser.people.each do |person|
    if person.active?
      eligible_users << {
        name: person.name,
        email: person.email
      }
    end
  end

  eligible_users

再來繼續重構:

Let person behave like a hash

接下來我們要命名一個 to_h 來組成 name + email 的 hash

  class Person
    def initialize(attributes)
      @attributes = attributes
    end

    def to_h
      {
        name: name,
        email: email
      }
    end

    def active?
      @attributes['active']
    end

    def email
      @attributes['emailAddress']
    end

    def name
      "#{@attributes['firstName']} #{@attributes['lastName']}"
    end
  end

程式碼也變得更直觀跟可讀性了

  response = Request.call('some_url')
  parser = PeopleParser.new(response)

  eligible_users = parser.people.select(&:active?).map(&:to_h)

參考資料

My blog


上一篇
冒險村29 - API - exchange_rate
系列文
冒險村-30 Day Ruby on Rails Tips Challenge30

尚未有邦友留言

立即登入留言