LoginSignup
3

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-03-15

fukuoka.ex代表のpiacereです
ご覧いただいて、ありがとうございます :bow:

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

なお、「Phoenix」は、ElixirのWebフレームワークです

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

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

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

また、以下コマンドで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()以外の関数も似たような形になっています)

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にできます

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で無いと通らない…という制約が残っています

{
  "post": 
  {
    "key": "value"
  }
}

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

{
  "key": "value"
}

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

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レスポンス返却ビューファイルを追加」で解説している通りです

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

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

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で生成される内容の解説」に詳しくメモしています

終わり

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

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

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

ページ左上の image.pngimage.png のクリックを、どうぞよろしくお願いします:bow:
ここの数字が増えると、書き手としては「ウケている」という感覚が得られ、連載を更に進化させていくモチベーションになりますので、もっとElixirネタを見たいというあなた、私達と一緒に盛り上げてください!:tada:

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
3