基于this answer,我知道如何使用Poison.decode/2
将JSON解析为结构:
defmodule User do
@derive [Poison.Encoder]
defstruct [:address]
end
defmodule Address do
@derive [Poison.Encoder]
defstruct [:street]
end
Poison.decode(response, as: %User{address: %Address{}})
但是我如何告诉菲尼克斯做同样的事情?如果我告诉我端点接受JSON,它将自动将其解析为地图:
defmodule MyAppWeb.Router do
use MyAppWeb, :router
pipeline :api do
plug :accepts, ["json"]
end
scope "/api/v1", MyAppWeb do
pipe_through :api
put "/endpoint", MyController, :put
end
end
defmodule MyController do
def put(conn, %{"_json" => map}) do
# Here, `map` is already parsed as a map. How can I tell Phoenix to
# parse it as a struct I choose like I can tell `Poison` to do so?
end
end
您不能编写类似控制器的动作
def create(conn, %Product{} = product) do
...
end
并且期望框架为您注入一个Ecto模式结构,因为在Elixir中,由于Erlang / Elixir的动态类型化性质,因此无法在运行时访问函数的参数类型(而不是参数类型)。
您的最佳镜头是Kernel.struct/2
def create(conn, params) do
# ALERT: this line causes memory leak!!!
params = params |> Enum.map(fn{k, v}-> {String.to_atom(k), v} end)
product = struct(Product, params)
...
end
但是,您不应该这样做,而是创建一个Ecto变更集。我想您已经知道该怎么做。