30

尝试使用 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管道。

我在想也许像 Railsrespond_to do |format| ...

4

2 回答 2

31

正如 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 检查接受标头并呈现.jsonor.html模板。

于 2015-06-03T16:14:23.973 回答
23

我不会推荐它(我会推荐有两个控制器并将你的逻辑移动到一个由两个控制器调用的不同模块中)但它可以完成。您可以共享一个控制器,但您仍然需要一个单独的管道来确保设置正确的响应类型 (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在 url 的末尾指定格式 - 但是我建议您为 API 和站点使用不同的 url。

于 2015-06-03T15:40:46.060 回答