PhoenixのAPIでキャメルケースとスネークケースを自動変換する

Phoenix で API サーバーを構築すると、基本的に JSON レスポンスに含まれるキーの名前はスネークケースとなります。しかし、JSON レスポンスを扱うクライアント側では言語の都合上キャメルケースを使用したいケースが考えられるでしょう。

これを簡単に実現するのが [proper_case](https://github.com/johnnyji/proper_case) です。proper_case は、map のキーをスネークとキャメルの間で相互に変換するライブラリですが、これをPhoenixプロジェクトで使用することで、キャメルとスネークの自動変換を可能とします。

以下の記事では、proper_case を使用した  キャメルとスネークに変換方法について説明します。

# 環境

本記事の内容は、以下の環境で動作確認をしています。


- Elixir: 1.7.2
- OTP: 21.0.5

# API サーバーの用意

説明を簡単にするために、ここでは `blogs` と `comments` というテーブルを持つブログ  の API を想定してみます。

`mix phx.new` コマンドから `json_app` という Phoenix プロジェクトを作成し、 router、 controller、 view をそれぞれ以下のように設定します。

```elixir:router.ex
defmodule JsonAppWeb.Router do
  use JsonAppWeb, :router

  pipeline :api do
    plug(:accepts, ["json"])
  end

  scope "/api", JsonAppWeb do
    pipe_through(:api)

    resources("/blogs", BlogController)
  end
end
```

```elixir:blog_controller.ex
defmodule JsonAppWeb.BlogController do
  use JsonAppWeb, :controller

  alias JsonApp.Contents
  alias JsonApp.Contents.Blog

  def index(conn, _params) do
    blogs = Contents.list_blogs()
    render(conn, "index.json", blogs: blogs)
  end
end
```

```elixir:blog_view.ex
defmodule JsonAppWeb.BlogView do
  use JsonAppWeb, :view
  alias JsonAppWeb.BlogView

  def render("blog.json", %{blog: blog}) do
    %{
      id: blog.id,
      blog_title: blog.blog_title,
      blog_body: blog.blog_body,
      comments: blog.blog_comments |> Enum.map(&comments(&1))
    }
  end

  def comments(comment) do
    %{
      comment: comment.comment,
      comment_by: comment.comment_by
    }
  end
end
```

上記のように設定した上で、 `/api/blogs` API をコールすると、次のようなレスポンスが返ってきます。

```json:JSONレスポンス
{
  "data": [
    {
      "id": 1,
      "comments": [
        {
          "comment_by": "Honda",
          "comment": "Congrats!"
        },
        {
          "comment_by": "Naomi",
          "comment": "Wow"
        }
      ],
      "blog_title": "First blog",
      "blog_body": "This is my first blog!"
    }
  ]
}
```

このような API のやりとりをキャメルケースにするために、次のセクションから proper_case の設定をしてみます。

# proper_case の使用
それでは、 [proper_case](https://github.com/johnnyji/proper_case) の README に従って設定を行いましょう。

## インストール
proper_case をインストールするために、`mix.exs` に proper_case のdepsを追加します。

```elixir
  defp deps do
    [
      {:proper_case, "~> 1.2"}
    ]
  end
```

## routerの設定

`router.ex` を開き、 `:api` の `pipeline` に対して `ProperCase.Plug.SnakeCaseParams` のplugを追加します。

```elixir
  pipeline :api do
    plug(:accepts, ["json"])
    plug(ProperCase.Plug.SnakeCaseParams)
  end
```

## configの設定

`config.exs` を開き、以下の設定を追加します。

```elixir
config :phoenix, :format_encoders, json: ProperCase.JSONEncoder.CamelCase
```

設定は以上です。view や controller は一切変更する必要がありません。

## APIのレスポンス確認

それでは、 `/api/blogs` のAPIレスポンスを再度確認してみましょう。

```json
{
  "data": [
    {
      "id": 1,
      "comments": [
        {
          "commentBy": "Honda",
          "comment": "Congrats!"
        },
        {
          "commentBy": "Naomi",
          "comment": "Wow"
        }
      ],
      "blogTitle": "First blog",
      "blogBody": "This is my first blog!"
    }
  ]
}
```

レスポンス内のJSONのキーが全てキャメルケースになっていることが確認できます。

また、ここで行なった変更により、APIへ渡すパラメータもキャメルケースとすることができます。例えば新たにblogをcreateする場合でも、 `blotTitle`、`blogBody` といったパラメータ名を指定してリクエストを送ることができます。この場合、plug で設定した `ProperCase.Plug.SnakeCaseParams` により、controller へと渡される各パラメータは自動的にスネークケースとなります。

このように `proper_case` を使用することで、クライアントはキャメルケース、Phoenixはスネークケースと、それぞれの言語仕様に従った形で変数名などの記述に集中することができます。とても便利ですね :innocent: