I'm starting to use Phoenix outside of tutorials for a small use case. So far great, but I'm a bit taken aback by the following.
I have a resource "recording" that I want to access at /api/recordings in JSON and at /recording with a template and the result being HTML.
Ideally the Ecto representation would be unique, and even part of the controller would also be shared?
Right now I either have to have 2 resources recordingAPI and recordingHTML, or 2 controllers and 1 resources.
Any exemple out there? I keep finding one or the other, but not something with the :api pipe and the :browser pipe used for the same resource.
Thanks
You can utilize phoenix accepts
plug and a combination of two different views/layouts
# router.ex
defmodule TestExWeb.Router do
use TestExWeb, :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 "/", TestExWeb do
pipe_through :browser
get "/recording", PageController, :index
end
scope "/api", TestExWeb do
pipe_through :api
get "/recording", PageController, :index
end
end
As you can see, :browser
uses :accepts ["html"]
while :api
uses :accepts ["json"]
. You can find this in the private struct of your conn
and use it in the controller like this:
defmodule TestExWeb.PageController do
use TestExWeb, :controller
def index(%{private: %{phoenix_format: format}} = conn, _params) do
data = "Hello World"
render(conn, "index.#{format}", data: data)
end
end
Now, you just need to tell phoenix how to render your json, html is already taken care of by page.html.eex
in layouts, so add the following to your page_view.ex
defmodule TestExWeb.PageView do
use TestExWeb, :view
def render("index.json", %{data: data}) do
%{
data: data
}
end
end
Two drawbacks with this solution: