LoginSignup
22
6

More than 5 years have passed since last update.

JSON処理をわかりやすくするGemを作った

Last updated at Posted at 2017-12-01

背景

RubyでのJson処理

RubyでAPIを叩いて処理するというコードを書くときがあるとします。
そのAPIレスポンスがJSONで以下のように帰ってくるとします。

sample.json
{
  "id": 1,
  "title": "テスト記事",
  "description": "説明文",
  "writer": {
    "id": 1,
    "name": "なまえ",
    "profile": "プロフィール ",
    "picture": {
      "id": 1,
      "url": "https://test.jp/test.jpg"
  },
  "tags": [
    {
      "id": 1,
      "name": "Ruby"
    },
    {
      "id": 2,
      "name": "Kotlin"
    }
  ],
  "picture": {
    "id": 1,
    "url": "https://test.jp/test.jpg"
  }
}

これをRubyで処理して、Articleとして保存というようなのを書こうとすると

url = 'APIのURL'
uri = URI::parse(url)
res = Net::HTTP.get(uri)
result = JSON.parse(res)

Post.create(title: result['title'], img_url: result['picture']['url'])

result['tags'].each do |tag|
  HashTag.create(name: tag['name'])
end

という風に書くことになると思います。

こういったようにハッシュ化されたJSONを扱う時以下のようなことが問題になります

  • レスポンスの形式が何処かにまとまっていない、書いた人の頭のなかにある
  • JSONが複雑になるほどコードが大変になる
  • テストしにくい

AndroidでのJson処理

Androidでは以下のように行えます。
※ KotlinでのRetrofit + Moshiの場合

data class Article(val id: Int,
                   val title: String,
                   val description: String,
                   val writer: Writer,
                   val tags: List<Tag>,
                   val picture: Picture)

data class Writer(val id: Int,
                  val name: String,
                  val profile: String,
                  val picture: Picture)

data class Tag(val id: Int,
               val name: String)

data class Picture(val id: Int,
                   val url: String)

上記の用に定義しておけばJSON形式のレスポンスを、POJO(Plain Old Java Object)へ変換してくれます。
APIのレスポンスをオブジェクトにして持っておくことで、色々な処理が楽になります。

今回作ったライブラリの目的は、JSON形式のレスポンスを、PORO(Plain Old Ruby Object)へ変換することです。
こういったような処理をRubyでも実現して、Json周りの簡略化を行おうとしました。

作ったライブラリ

使い方

Ruson::Baseを継承したモデルを作ります
fieldsというメソッドを定義して、その中にfieldを定義していきます。

class Article < Ruson::Base
  def fields
    field :id
    field :title
    field :description
    field :writer, class: Writer
    field :tags, each_class: Tag
    field :picture, class: Picture
  end
end

class Writer < Ruson::Base
  def fields
    field :id
    field :name
    field :profile
    field :picture, class: Picture
  end
end

class Tag < Ruson::Base
  def fields
    field :id
    field :name
  end
end

class Picture < Ruson::Base
  def fields
    field :id
    field :url
  end
end

これらを使ってさっきのコードを書き直すと

url = 'APIのURL'
uri = URI::parse(url)
res = Net::HTTP.get(uri)
article = Article.new(res)

Post.create(title: article.title, img_url: article.picture.url)

article.tags.each do |tag|
  HashTag.create(name: tag.name)
end

という風にわかりやすく書くことができます

また作成したオブジェクトにメソッドを持たせて

class Article < Ruson::Base
  def fields
    field :id
    field :title
    field :description
    field :writer, class: Writer
    field :tags, each_class: Tag
    field :picture, class: Picture
  end

  def save
    Post.create(title: title, img_url: picture.url)
  end
end

という風に書けばロジックをオブジェクトに移せるので可読性が上がるかもしれません。

具体的な使い方

基本

class Article < Ruson::Base
  def fields
    field :id
    field :title
  end
end

fieldで指定したものは、

article.id
article.title

と呼べます

ルートパラメータがある時

{
  "article": {
    "id": 1,
    "title": "テスト記事",
    "description": "説明文"
  }
}
article = Article.new(res, root: 'article')

と指定して下さい

名前を変えたい時

class Article < Ruson::Base
  def fields
    field :id
    field :text, name: 'title'
  end
end

とすればJsonのtitleという要素をtextに入れてくれます。

ネストしたクラスがある時

class Article < Ruson::Base
  def fields
    field :writer, class: Writer
  end
end

上記の用に指定すると、指定したクラスのオブジェクトに変換します。

ネストしたクラスのリストがある時

class Article < Ruson::Base
  def fields
    field :tags, each_class: Tag
  end
end

上記の用に指定すると、指定したクラスのオブジェクトの配列に変換します。

つぶやき

  • 本当は、StringとかInteger、Nullableなどいろいろ指定したかったんですが、RubyにBooleanクラスがなくて、そこで躓いたので、一旦は断念。
  • fieldsで囲む必要が無いようにしたかったけど、方法が思いつかなかったので今の方法にしました。
  • もしかすると似たようなライブラリがあるかもしれないです

明日は@higopageさんの「Unityアプリを作ったときにやったことをまとめました。」です。

22
6
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
22
6