Elixir Phoenix将JSON解析为结构

问题描述 投票:0回答:2

基于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
elixir phoenix-framework
2个回答
1
投票

在您的endpoint.ex中,您应该有parsers插头:

 plug Plug.Parsers,
    parsers: [:urlencoded, :multipart, :json],
    pass: ["*/*"],
    json_decoder: Poison

删除json原子,应禁用json解析器。


0
投票

您不能编写类似控制器的动作

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变更集。我想您已经知道该怎么做。

© www.soinside.com 2019 - 2024. All rights reserved.