Elixir Phoenix-具有多重渲染的控制器

Elixir Phoenix-具有多重渲染的控制器,elixir,phoenix-framework,Elixir,Phoenix Framework,尝试使用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 e

尝试使用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 |…

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

我不建议这样做(我建议使用两个控制器,并将您的逻辑移到由两个控制器调用的不同模块中),但这是可以做到的。您可以共享一个控制器,但仍然需要一个单独的管道来确保设置了正确的响应类型(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.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

然后,您可以在url末尾使用
?format=json
指定格式-我建议您的API和站点使用不同的url。

正如Gazler所说,使用单独的管道可能是最好的选择,但是,在相同的控制器动作上进行模式匹配可以愉快地完成类似的操作:

def show(conn, %{"format" => "html"} = params) do
  # ...
end

def show(conn, %{"format" => "json"} = params) do
  # ...
end
或者,如果函数体相同,并且您只希望基于accept标头呈现模板,则可以执行以下操作:

def show(conn, params) do
  # ...

  render conn, :show
end

传递atom作为模板名称将导致phoenix检查accept标头并呈现
.json
.html
模板。

正如Gazler所说,使用单独的管道可能是最好的选择,但在相同的控制器操作上进行模式匹配可以很好地做到这一点:

def show(conn, %{"format" => "html"} = params) do
  # ...
end

def show(conn, %{"format" => "json"} = params) do
  # ...
end
或者,如果函数体相同,并且您只希望基于accept标头呈现模板,则可以执行以下操作:

def show(conn, params) do
  # ...

  render conn, :show
end

传递atom作为模板名称将导致phoenix检查accept标头并呈现
.json
.html
模板。

您不需要插入格式,您可以使用atom作为模板,accept标头将用于呈现正确的格式。@ChrisMcCord谢谢-我做了一些尝试,但无法使内容类型标头正常工作。我会更新我的答案。@gazler如果多个控制器是解决方案,我们应该如何命名它们以使它们既不同又独立?API控制器应该进入controllers/API/user_controller.exs吗?您不需要插入格式,您可以使用atom作为模板,accept标头将用于呈现正确的格式。@ChrisMcCord谢谢-我尝试了一些方法,但无法使内容类型标头正常工作。我会更新我的答案。@gazler如果多个控制器是解决方案,我们应该如何命名它们以使它们既不同又独立?API控制器应该进入controllers/API/user_controller.exs吗?它看起来不像传入的
params
中有
格式
?这个答案之后有什么变化吗?这个答案似乎不再有效了。但是,您可以进行模式匹配,如
def index(%%{private:%%{phoenix_format:“json”}}=conn,params)do
。我不知道这是安全的还是建议的。看起来传入的
params
中没有
format
?这个答案之后有什么变化吗?这个答案似乎不再有效了。但是,您可以进行模式匹配,如
def index(%%{private:%%{phoenix_format:“json”}}=conn,params)do
。我不知道这是安全的还是建议的。