【问题标题】:Elixir Multiple Jason Encoders for same struct相同结构的 Elixir 多个 Jason 编码器
【发布时间】:2020-08-29 23:41:03
【问题描述】:

假设我正在构建一个版本化的 API(例如,让我们使用一个用户对象):

%User{
  id: "b2507407-891b-486e-aaf8-ba262c16d618"
  first_name: "John",
  last_name: "Doe",
  email: "john@doe.com"
}

我最初的想法是为不同版本的 API 提供多个编码器,我将运行不同的 Jason 编码器:

defimpl Jason.EncoderV1, for: __MODULE__ do
  def encode(user, opts) do
    Jason.Encode.map(%{name: "#{user.first_name} #{user.last_name}"}, opts)
  end
end

defimpl Jason.EncoderV2, for: __MODULE__ do
  def encode(user, opts) do
    Jason.Encode.map(%{first_name: first_name, last_name: last_name}, opts)
  end
end

我在 Jason 文档中没有看到任何允许这样做的参考。

【问题讨论】:

    标签: json elixir elixir-jason


    【解决方案1】:

    您应该以某种方式告诉Jason 您要使用哪个版本。 Jason.Encoder.encode/2 有第二个参数。

    defimpl Jason.Encoder, for: __MODULE__ do
      def encode(user, opts) do
        {v, opts} = Keyword.pop(opts, :version, :v1)
    
        v
        |> case do
          :v2 -> %{first_name: first_name, last_name: last_name}
          _ -> %{name: "#{user.first_name} #{user.last_name}"}
        end
        |> Jason.Encode.map(opts)
      end
    end
    

    并称它为Jason.encode!(any, version: :v2)

    旁注:defimpl 期望将协议定义为第一个参数的模块,不能传递任何内容,例如那里不存在的 Jason.EncoderV2

    【讨论】:

    • 您似乎无法将任意选项传递给编码器
    【解决方案2】:

    您的示例代码提出的问题更像是关于 Elixir protocols 的问题,但请注意:Jason package defines its own protocol 不受您的版本控制 - 即您的实现将始终使用 defimpl Jason.Encoder

    但是,您可以为不同的结构定义不同的实现,例如

    defimpl Jason.Encoder, for: UserV1 do
      def encode(user, opts) do
        Jason.Encode.map(%{name: "#{user.first_name} #{user.last_name}"}, opts)
      end
    end
    
    defimpl Jason.Encoder, for: UserV2 do
      def encode(user, opts) do
        Jason.Encode.map(%{first_name: first_name, last_name: last_name}, opts)
      end
    end
    

    或者,利用 Aleksei 在他的回答中指出的选项(第二个参数)。

    换句话说,您无法更改协议的名称(因为它不在您的控制范围内),但您可以通过提供不同模块的不同名称来更改功能(其中 你控制)。

    这里更简单的解决方案没有协议实现那么迷人:

    1. 您可以简单地为您的不同用例定义 JSON 视图
    2. 您可以编写自定义v1v2 函数,将%User{} 结构转换为常规映射(每个都需要任何字段),然后依赖JSON 提供的标准JSON 编码库(在您的情况下为Jason)及其编码协议。

    【讨论】:

    • 更简单的选项不适用于嵌套术语%{foo: :bar, user: %User{}},这是该协议存在的要点。
    猜你喜欢
    • 1970-01-01
    • 2021-01-08
    • 2016-03-14
    • 2016-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多