1. FL4TLiN3

    Posted

    FL4TLiN3
Changes in title
+PhoenixでJSONを返すWeb APIを作る
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,102 @@
+※ Phoenix 1.0.3
+
+# やること
+
+1. `mix phoenix.gen.html`する
+2. RouterにAPIリクエストを受けるためのpipelineを設定する
+2. ControllerでContent Negotiationを指定する
+3. ViewにJSONを返すよう記述する
+
+## 1. 事前準備
+
+以下を実行
+
+```zsh
+mix phoenix.gen.html Note notes title:string description:text
+```
+
+`mix phoenix.gen.json`というタスクもあり、こちらはすぐにAPIを用意したいだけなら十分なコードが生成される。ただし管理に便利なWebUIは自動生成されないため、今回は`mix phoenix.gen.html`の方を使う。
+
+## 2. Router
+
+この辺はrouter.exにコメント書きされているのでなんとなくわかる。
+
+```web/router.ex
+defmodule Demo.Router do
+ use Demo.Web, :router
+
+ pipeline :browser do
+ plug :accepts, ["html"]
+ plug :fetch_session
+ plug :fetch_flash
+ plug :protect_from_forgery
+ plug :put_secure_browser_headers
+ end
+
+ pipeline :api do
+ plug :accepts, ["json"]
+ end
+
+ scope "/", Smaug do
+ pipe_through :browser
+
+ get "/", PageController, :index
+ resources "/notes", NoteController
+ end
+
+ scope "/api", Smaug do
+ pipe_through :api
+
+ resources "/notes", NoteController, only: [:index, :show]
+ end
+end
+```
+
+`plug :accepts, ["json"]`を指定することで、`Accept: application/json`のあるHTTP Requestのみを許可してくれる。
+
+また、`resources/3`でAPIとして公開するメソッドを制限できる。
+
+## 3. Controller
+
+生成されたControllerには、Templateのファイル名がStringでベタ書きされている。これだと`Accept: application/json`を指定したHTTP Requestを飛ばしてもContent Negotiationが行われない。
+
+そこで、以下のようにAtomで指定する。
+
+```web/controllers/note_controller.ex
+#(該当箇所のみ抜粋)
+def index(conn, _params) do
+ notes = Repo.all(Note)
+ # render(conn, "index.html", notes: notes)
+ render(conn, :index, notes: notes)
+end
+```
+
+## 4. View
+
+mixが生成したViewだとJSONへのencodingが行われず、poisonがエラーを出す。そのため以下のようにViewを修正する。
+
+```web/views/note_view.ex
+defmodule Demo.NoteView do
+ use Demo.Web, :view
+
+ def render("index.json", %{notes: notes}) do
+ %{data: render_many(notes, Demo.NoteView, "note.json")}
+ end
+
+ def render("show.json", %{story: story}) do
+ %{data: render_one(note, Demo.NoteView, "note.json")}
+ end
+
+ def render("note.json", %{note: note}) do
+ %{id: note.id,
+ title: note.title,
+ description: note.description}
+ end
+end
+```
+
+## 確認
+
+```zsh
+curl 'http://localhost:4000/api/notes' -v -X GET -H 'Accept: application/json'
+```