LoginSignup
6
1

More than 1 year has passed since last update.

既存APIのリネーム②:リクエストJSON、レスポンスJSON

Last updated at Posted at 2019-03-21

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

前回に引き続き、mix phx.gen.jsonで自動生成したAPIのリネームをしたいとき、どこを直す必要があり、直さなくて良いところがどこか、イマイチ分かりにくいので、まとめてみました

後半は、「リクエストJSON」と「レスポンスJSON」のリネームです

なお、「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

リクエストJSONのキーを変更するとき

「POST」と「PUT」が、リクエストJSONのキーを要求するので、コントローラのcreate()とupdate()を変更する必要があります

いずれも、関数パターンマッチで実装されているので、マッチするパターンを変更するだけです

lib/api_sample_web/controllers/post_controller.ex
defmodule ApiSampleWeb.PostController do
  
  def create(conn, %{"hoge" => post_params}) do
    # modify here------^
    with {:ok, %Post{} = post} <- Api.create_post(post_params) do
      conn
      |> put_status(:created)
      |> put_resp_header("location", Routes.post_path(conn, :show, post))
      |> render("show.json", post: post)
    end
  end
  
  def update(conn, %{"id" => id, "hoge" => post_params}) do
    # modify here------------------^
    post = Api.get_post!(id)

    with {:ok, %Post{} = post} <- Api.update_post(post, post_params) do
      render(conn, "show.json", post: post)
    end
  end
  

リクエストJSON

リクエストJSONのキーを無くしたいとき

そもそも、キーを無くしたい場合は、以前書いた、「mix phx.gen.jsonで作った既存APIの非DB化」の「リクエストJSONのバリデーションを解除する」をご参考ください

レスポンスJSON

レスポンスJSONのキーを変更するとき

Phoenixの自動生成JSON APIは、レスポンスJSONに「data」というキーを付与します

{
  "data":
  [
    { 
      "id":   1,
      "title":"t1",
      "body": "b1"
    }
  ]
}

これを以下のように変更します

{
  "hoge":
  [
    { 
      "id":   1,
      "title":"t1",
      "body": "b1"
    }
  ]
}

これを行うには、ビューのrender()2箇所の「%{data:~}」の「data」の部分を変更します

lib/api_sample_web/views/post_view.ex
defmodule ApiSampleWeb.PostView do
  def render("index.json", %{post: post}) do
    %{hoge: render_many(post, PostView, "post.json")}
    #  ^---modify here
  end

  def render("show.json", %{post: post}) do
    %{hoge: render_one(post, PostView, "post.json")}
    #  ^---modify here
  end
  

レスポンスJSONのキーを無くしたいとき

Phoenixの自動生成JSON APIは、レスポンスJSONに「data」というキーが付与されますが、Vue.jsのaxiosなんかでこれを取得すると、response.data.dataみたいな書き方になり、ウザイので、キーを無くし、response.dataで取得できるようにしたい…なんてケースがあります

レスポンスJSONで言うと、以下のようにしたいときです

{
  [
    { 
      "id":   1,
      "title":"t1",
      "body": "b1"
    }
  ]
}

これを行うには、ビューのrender()2箇所から、「data」で包むコードを削除します

lib/api_sample_web/views/post_view.ex ※変更前
defmodule ApiSampleWeb.PostView do
  
  def render("index.json", %{post: post}) do
    %{data: render_many(post, PostView, "post.json")}
  end

  def render("show.json", %{post: post}) do
    %{data: render_one(post, PostView, "post.json")}
  end
  
lib/api_sample_web/views/post_view.ex ※変更後
defmodule ApiSampleWeb.PostView do
  
  def render("index.json", %{post: post}) do
    render_many(post, PostView, "post.json")
    # ^---%{data:} removed
  end

  def render("show.json", %{post: post}) do
    render_one(post, PostView, "post.json")
    # ^---%{data:} removed
  end
  

コントローラからビューに渡すキーを変更したいとき

コードをキレイにしたいという観点で、リクエストJSONのキーだけで無く、コントローラからビューに渡すキーを変更したい場合は、render()呼び出しの第2引数のキーを変更し、受け側のビューのrender()も変更します

ついでに各種ローカル変数も変更しています(これは必須ではありませんが、変えておいた方が無難です)

lib/api_sample_web/controllers/post_controller.ex
defmodule ApiSampleWeb.PostController do
  
  def index(conn, _params) do
    hoge = Api.list_post()
    # ^---modify here
    render(conn, "index.json", hoge: hoge)
    # modify here------^--------^-----^
  end

  def create(conn, %{"hoge" => hoge_params}) do
    # modify here------^--------^
    with {:ok, %Post{} = hoge} <- Api.create_post(hoge_params) do
      # modify here-------^------------------------^
      conn
      |> put_status(:created)
      |> put_resp_header("location", Routes.post_path(conn, :show, hoge))
      # modify here-------------------------------------------------^
      |> render("show.json", hoge: hoge)
      # modify here-----------^-----^
    end
  end

  def show(conn, %{"id" => id}) do
    post = Api.get_post!(id)
    render(conn, "show.json", hoge: hoge)
    # modify here--------------^-----^
  end

  def update(conn, %{"id" => id, "hoge" => hoge_params}) do
    # modify here------------------^--------^
    hoge = Api.get_post!(id)
    # ^---modify here

    with {:ok, %Post{} = post} <- Api.update_post(hoge, hoge_params) do
      # modify here-------^------------------------^-----^
      render(conn, "show.json", hoge: hoge)
      # modify here--------------^-----^
    end
  end

  def delete(conn, %{"id" => id}) do
    post = Api.get_post!(id)
    # ^---modify here

    with {:ok, %Post{}} <- Api.delete_post(post) do
      # modify here-------------------------^
      send_resp(conn, :no_content, "")
    end
  end
lib/api_sample_web/views/post_view.ex
defmodule ApiSampleWeb.PostView do
  
  def render("index.json", %{hoge: hoge}) do
    # modify here-------------^-----^
    %{data: render_many(hoge, PostView, "post.json")}
    # modify here--------^
  end

  def render("show.json", %{hoge: hoge}) do
    # modify here-------------^-----^
    %{data: render_one(hoge, PostView, "post.json")}
    # modify here-------^
  end
  

なお、DBスキーマや、それに紐付く構造体(%Post{})、およびモジュール名まで変更する場合は、上記の続きを「気合い」で書き換えていくことも可能ですが、自動生成し直した方が速いと思われます

レスポンスをJSONでは無くテキストにしたい

render()の第一引数を index.json から index.txt に変更すれば、JSONからテキストに変更できます

ちなみに、あたかもファイル名のように見えますが、 index.jsonindex.txt というファイルが存在する訳ではありません

lib/api_sample_web/views/post_view.ex
defmodule ApiSampleWeb.PostView do
  
  def render("index.txt", %{hoge: hoge}) do
    # modify here----^
    "hoge, foo"  # <--modify here
  end

  def render("show.txt", %{hoge: hoge}) do
    # modify here---^
    "hogehoge"  # <--modify here
  end
  

終わり

既存APIのリクエストJSON、レスポンスJSONをリネームする方法について解説しました

APIを自動生成する際にミスってしまったときや、自動生成したものに機能追加を行った後にリネームしたい、なんてときには、ご参考ください

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

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

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