fukuoka.ex代表のpiacereです
ご覧いただいて、ありがとうございます
以前、書いた「mix phx.gen.jsonを使わず気軽に作れるPhoenix APIの逆バージョンで、mix phx.gen.jsonで既に作成済のJSON APIを、DBを利用しないAPIに変更する方法について解説します
なお、「Phoenix」は、ElixirのWebフレームワークです
内容が、面白かったり、役に立ったら、「いいね」よろしくお願いします
本コラムの検証環境、事前構築のコマンド
本コラムは、以下環境で検証しています(Windowsで実施していますが、Linuxやmacでも動作する想定です)
- Windows 10
- Elixir 1.8.1 ※最新版のインストール手順はコチラ
- Phoenix 1.4.0 ※最新版のインストール手順はコチラ
- PostgreSQL 10.1 ※最新版のインストール手順はコチラ
また、以下コマンドで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()以外の関数も似たような形になっています)
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にできます
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で無いと通らない…という制約が残っています
{
"post":
{
"key": "value"
}
}
これを、以下のような、キー付きオブジェクトで包まない形にしたい…なんて要望もあると思います
{
"key": "value"
}
そのときは、第2引数の関数パターンマッチを解除すれば、どんなリクエストJSOでも受け付けるようにできます(結果的に、以前のコラムと同じ形の、最小限のコントローラになりました)
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レスポンス返却ビューファイルを追加」で解説している通りです
裏技的:コントローラで直接JSON返却を行う
ビューのrender()を変更する以外に、コントローラからrender()の呼び出しを消し、直接、Phoenix.Controllerモジュールにあるjson()を使って、JSONを返却するという裏技もあります
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で生成される内容の解説」に詳しくメモしています
終わり
Phoenixが自動生成した、DB連動JSON APIを、非DB化してみました
既に作成済みのDB連動JSON APIを、空振りさせたり、外部API接続にスイッチしたい場合、あとはMnesia/RedisのようなインメモリDBにスイッチしたい場合は、このテクニックを使ってみてください
p.s.「いいね」よろしくお願いします
ページ左上の や
のクリックを、どうぞよろしくお願いします
ここの数字が増えると、書き手としては「ウケている」という感覚が得られ、連載を更に進化させていくモチベーションになりますので、もっとElixirネタを見たいというあなた、私達と一緒に盛り上げてください!