Render different formats in Phoenix

Sylvain Kieffer
1 min readJan 20, 2016

--

EDIT : In fact Phoenix.Controller.render accepts an atom (ex : :index) for the template, and chooses the format accordingly. So you can write render(conn, :index, posts: posts) without using get_format.
See
here and there.

Say I have a Post resource. I define a /posts route. Then, using the same URL, I want to be able to get either a HTML response or a JSON one.

I can ask Phoenix for a specific format either by setting the Accept header, or by passing a _format param, for instance using the url /posts?_format=json. The format can then be fetched using Phoenix.Controller.get_format/1.

The index action (/posts) looks initially like this :

def index(conn, _params) do
posts = Post |> Repo.all()
render conn, "index.html", posts: posts
end

The first step is to add “json” to the :accepts plug in the router :

pipeline :browser do
plug accepts, ["html", "json"]
...
end

Then I add a render(“index.json”, assigns) function to PostView :

def render("index.json", %{posts: posts}) do
posts
|> Enum.map(fn post -> Map.take([:title, :body]) end)
end

Finally I change the index action :

def index(conn, _params) do
posts = Repo.all(Post)
render conn, "index." <> get_format(conn), posts: posts
end

Now if I visit /posts?_format=json I get the appropriate format. /posts doesn’t change : it renders HTML.

--

--