※ Phoenix 1.0.3
やること
-
mix phoenix.gen.html
する - RouterにAPIリクエストを受けるためのpipelineを設定する
- ControllerでContent Negotiationを指定する
- ViewにJSONを返すよう記述する
1. 事前準備
以下を実行
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
確認
curl 'http://localhost:4000/api/notes' -v -X GET -H 'Accept: application/json'