尝试使用Elixir + Phoenix创建一个应用程序,它可以处理“浏览器”和“api”请求以处理其资源。
是否可以这样做而不必做那样的事情:
scope "/", App do
pipe_through :browser
resources "/users", UserController
end
scope "/api", App.API as: :api do
pipe_through :api
resources "/users", UserController
end
这意味着必须创建两个控制器,这些控制器可能具有相同的行为,除了它将使用浏览器管道呈现HTML,而使用JSON来呈现 api 管道。
我想的可能就像Rails respond_to do |format| ...
答案 0 :(得分:30)
正如Gazler所说,你可能最好通过使用单独的管道服务,但是在同一控制器操作上使用模式匹配可以很愉快地完成这样的事情:
def show(conn, %{"format" => "html"} = params) do
# ...
end
def show(conn, %{"format" => "json"} = params) do
# ...
end
或者如果函数体是相同的,并且您只想基于接受头呈现模板,则可以执行以下操作:
def show(conn, params) do
# ...
render conn, :show
end
传递一个atom作为模板名称将导致phoenix检查接受标头并呈现.json
或.html
模板。
答案 1 :(得分:22)
我不推荐它(我建议有两个控制器并将你的逻辑移动到两个控制器调用的不同模块中)但是可以完成。您可以共享控制器,但仍需要一个单独的管道来确保设置正确的响应类型(html / json)。
以下将使用相同的控制器和视图,但根据路径渲染json或html。 " /"是html," / api"是json。
路由器:
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
控制器:
defmodule ScopeExample.PageController do
use ScopeExample.Web, :controller
plug :action
def index(conn, params) do
render conn, :index
end
end
查看:
defmodule ScopeExample.PageView do
use ScopeExample.Web, :view
def render("index.json", _opts) do
%{foo: "bar"}
end
end
如果使用路由器,您也可以共享路由器,并使用相同的路由提供所有服务:
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
然后,您可以在网址末尾使用?format=json
指定格式 - 但我建议您使用不同的网址和API网站。