0
0

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 3 years have passed since last update.

form形式でレスポンスを返したい時に使えるオブジェクト指向設計

Last updated at Posted at 2020-12-29

背景

現在開発中のシステムのバックエンドを担当しており、一部のAPIレスポンスを 「form形式で返す」というような実装をしました。この時に用いた設計が汎用的だなと思ったので記事にしようと思いました。

本質的な意味合いは異なりますが、見方によってはデザインパターンでいうアダプタっぽいかなと思っています。正しいかどうかは定かではないです。。

言語はruby、フレームワークはrailsを想定しています。

要件

Testsテーブル

カラム
id int8
first varchar(255)
second varchar(255)

上記のようなテーブルがあり、その1レコードを以下のようなJSONレスポンス形式で返したいとします。

{
	"form_items" : [
		{
			"item_name" : "first",
			"value" : "hoge" # firstカラムの値
		},
		{
			"item_name" : "second",
			"value" : "fuga" # secondカラムの値
		}
	]
}

実際のシステムではitem_name, valueだけでなくメタデータなどが含まれて複雑な構造になっているのですが、今回は便宜上シンプルな設計にしています。今後カラム数が増えて1つ1つのカラムに対してform_itemsの配列の要素が比例すると想定してください。

設計と実装

5つのクラスを用意しました。

3つはFieldを定義するクラスです。抽象クラスとしてFieldBaseクラスを作成しています。

一見なぜこのような設計したか疑問に思うかもしれませんが、カラムとカラムに付随するメタデータが増えることを考えるとこのような設計が無難かなと思いました。


class FirstField < FieldBase
  COLUMN_NAME = 'first'
end

class SecondField < FieldBase
  COLUMN_NAME = 'second'
end

class Base
  def initialize(record)
    @record = record
  end

  def value
    @record.send(self.class::COLUMN_NAME)
  end
end

4つ目と5つ目はセットで説明します

まず、FormItemクラスではitem_nameとvalueのセットをインスタンスとして保持するために作成しています。具体的には5つ目のクラスを見ればわかると思います。

class FormItem
  attr_reader :item_name, :value

  def initialize(field_instance)
    @item_name = field_instance.class::COLUMN_NAME
    @value = field_instance.value
  end
end

5つ目はform_itemの配列を作成するクラスです

class FormItemList
  attr_reader :form_items

  def initialize(record)
    @form_items = []

    # 以下form_itemの順番がレスポンスとして送るformの順番に直結する
    form_item(FirstField.new(record))
    form_item(SecondField.new(record))
  end

  private

  def form_item(field_instance)
    @form_items += [FormItem.new(field_instance)]
  end
end

あとは以下のようにcontrollerで呼び出してあげると、form形式にオブジェクト化されたものが要素となる配列が得られます

record = Test.first
form_items = FormItemList.new(record).form_items

pp form_items
# => [FirstFieldインスタンスから作成したFormItemインスタンス, FirstFieldインスタンスから作成したFormItemインスタンス]

ここまできたら配列内のオブジェクトをjsonへserializeするだけです。

serializeの方法は色々あるので説明は省きます。

まとめ

カラム数やメタデータが少ないとあまり恩恵を受けられていないように感じますが、増えた際にカスタマイズしやすいようになっているのがよかったかなと思います!

最近Twitterを始めたので是非フォローお願いいたします!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?