mix phx.gen.jsonで作った既存APIの非DB化

[fukuoka.ex](https://fukuokaex.connpass.com/)代表のpiacereです
ご覧いただいて、ありがとうございます :bow:

以前、書いた[「mix phx.gen.jsonを使わず気軽に作れるPhoenix API](https://qiita.com/piacere_ex/items/a689b886f88249901a88)の逆バージョンで、mix phx.gen.jsonで既に作成済のJSON APIを、DBを利用しないAPIに変更する方法について解説します

なお、[「Phoenix」](https://qiita.com/piacerex/items/b7787580fce5f148242f#phoenix%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)は、ElixirのWebフレームワークです

内容が、面白かったり、役に立ったら、「いいね」よろしくお願いします :wink:

# 本コラムの検証環境、事前構築のコマンド

本コラムは、以下環境で検証しています（Windowsで実施していますが、Linuxやmacでも動作する想定です）

- Windows 10
- Elixir 1.8.1　　　　※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacere_ex/items/6714e1440e3f25fb46a1#%E4%BA%8B%E5%89%8D%E6%BA%96%E5%82%99elixir%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)</b>
- Phoenix 1.4.0 　　 ※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacere_ex/items/b7787580fce5f148242f#phoenix%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)</b>
- PostgreSQL 10.1 　※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacere_ex/items/a7558adc6856e3577dc6#postgresql%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)</b>

また、以下コマンドでPhoenix PJ＋JSON APIを構築しています

```
mix phx.new api_sample --no-webpack
cd api_sample 
mix ecto.create
mix phx.gen.json Api Post post title:string body:string
mix ecto.migrate
【手動でルーティング追加とprotect_from_forgery無効化をする】
iex -S mix phx.server
```

# コントローラからDB操作を消す

mix phx.gen.jsonで作成した、コントローラの関数を見ると、以下のように、DB操作を行った後、render()を呼び出して、ビューを利用する構造になっています（create()以外の関数も似たような形になっています）

```elixir:lib/api_sample_web/controllers/post_controller.ex
defmodule ApiSampleWeb.PostController do
…
  def create(conn, %{"post" => post_params}) do
    with {:ok, %Post{} = post} <- Api.create_post(post_params) do
      conn
      |> put_status(:created)
      |> put_resp_header("location", post_path(conn, :show, post))
      |> render("show.json", post: post)
    end
  end
…
```

ここからDB操作を削除し、任意の何らかの処理を行った後、render()を呼ぶ形に変更すると、DB利用をしないJSON APIにできます

```elixir:lib/api_sample_web/controllers/post_controller.ex
defmodule ApiSampleWeb.PostController do
…
  def create(conn, %{"post" => post_params}) do
    【何らかの処理】
    render( conn, "show.json", post: "value" )
  end
…
```

厳密には、この後、DB操作をするRepo関連モジュールも削除するべきですが、いったんの最低限は、コレでOKです

# リクエストJSONのバリデーションを解除する

mix phx.gen.jsonで生成したContoroller関数の引数は、JSONデータに、「"post":」というキーを持つオブジェクトで包むバリデーションが、第2引数の関数パターンマッチによって効いているため、以下のようなリクエストJSONで無いと通らない…という制約が残っています

```json
{
  "post": 
  {
    "key": "value"
  }
}
```

これを、以下のような、キー付きオブジェクトで包まない形にしたい…なんて要望もあると思います

```json
{
  "key": "value"
}
```

そのときは、第2引数の関数パターンマッチを解除すれば、どんなリクエストJSOでも受け付けるようにできます（結果的に、[以前のコラム](https://qiita.com/piacere_ex/items/a689b886f88249901a88)と同じ形の、最小限のコントローラになりました）

```elixir:lib/api_sample_web/controllers/post_controller.ex
defmodule ApiSampleWeb.PostController do
  use ApiSampleWeb, :controller
…
  def create( conn, request ) do
    【何らかの処理】
    render( conn, "show.json", post: "value" )
  end
…
```

# 任意のレスポンスJSONを返却する

ここは、[以前のコラム「mix phx.gen.jsonを使わず気軽に作れるPhoenix API」の「APIレスポンス返却ビューファイルを追加」](https://qiita.com/piacere_ex/items/a689b886f88249901a88#api%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E8%BF%94%E5%8D%B4%E3%83%93%E3%83%A5%E3%83%BC%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%BF%BD%E5%8A%A0)で解説している通りです

# 裏技的：コントローラで直接JSON返却を行う

ビューのrender()を変更する以外に、コントローラからrender()の呼び出しを消し、直接、Phoenix.Controllerモジュールにあるjson()を使って、JSONを返却するという裏技もあります

```elixir:lib/api_sample_web/controllers/post_controller.ex
defmodule ApiSampleWeb.PostController do
  use ApiSampleWeb, :controller
…
  def create(conn, %{"post" => post_params}) do
    【何らかの処理】
    json( conn, %{ post: "value" } )
  end
…
```

こうなると、「ビューのrender()って、何のためにあるの？」となりがちですが、render()は、index()のような複数件の同じデータを返却する関数のと、show()のような1件返却する関数をのどちらもカバーするような作りになっているので、そういう造りをしたいときに有用です

ここの造りは、[以前のコラム「mix phx.gen.jsonを使わず気軽に作れるPhoenix API」の「オマケ：mix phx.gen.jsonで生成される内容の解説」](https://qiita.com/piacere_ex/items/a689b886f88249901a88#%E3%82%AA%E3%83%9E%E3%82%B1mix-phxgenjson%E3%81%A7%E7%94%9F%E6%88%90%E3%81%95%E3%82%8C%E3%82%8B%E5%86%85%E5%AE%B9%E3%81%AE%E8%A7%A3%E8%AA%AC)に詳しくメモしています

# 終わり

Phoenixが自動生成した、DB連動JSON APIを、非DB化してみました

既に作成済みのDB連動JSON APIを、空振りさせたり、外部API接続にスイッチしたい場合、あとはMnesia／RedisのようなインメモリDBにスイッチしたい場合は、このテクニックを使ってみてください

# p.s.「いいね」よろしくお願いします

ページ左上の ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/4d515047-cc48-382e-c2b1-3ad0cc50dbbf.png) や ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/a4e3da58-70a3-4197-95a2-6a6906650d01.png) のクリックを、どうぞよろしくお願いします:bow:
ここの数字が増えると、書き手としては「ウケている」という感覚が得られ、連載を更に進化させていくモチベーションになりますので、もっとElixirネタを見たいというあなた、私達と一緒に盛り上げてください！:tada: