I wouldn't recommend it (I would recommend having two controllers and move your logic into a different module that is called by both controllers) but it can be done. You can share a controller, but you still need a separate pipeline to ensure the correct response type (html/json) is set.
The following will use the same controller and view, but render json or html depending on the route. "/" is html, "/api" is json.
Router:
defmodule ScopeExample.Router do
use ScopeExample.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", ScopeExample do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
scope "/api", ScopeExample do
pipe_through :api # Use the default browser stack
get "/", PageController, :index
end
end
Controller:
defmodule ScopeExample.PageController do
use ScopeExample.Web, :controller
plug :action
def index(conn, params) do
render conn, :index
end
end
View:
defmodule ScopeExample.PageView do
use ScopeExample.Web, :view
def render("index.json", _opts) do
%{foo: "bar"}
end
end
You can also share the router and have everything served by the same route if you use a router like:
defmodule ScopeExample.Router do
use ScopeExample.Web, :router
pipeline :browser do
plug :accepts, ["html", "json"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
end
scope "/", ScopeExample do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
end
You can then specify the format using ?format=json
at the end of the url - I would recommend going with different urls for your API and site however.