首页 > 解决方案 > Elixir - 将 http 响应 json 转换为 ecto.schema 对象

问题描述

我是长生不老药的新手。我有一个 Ecto Schema

  defmodule MyScoreSchema do
  use Ecto.Schema
  import Ecto.Changeset

  schema "historical_extra_fuels" do
    field :average, :float
    field :count, :float
    field :percent, :float
    field :name, :string
  end


  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:average, :count, :percent])
    |> validate_required([])
  end
end

和父模式

defmodule OverallScore do
  use Ecto.Schema
  import Ecto.Changeset

  schema "OverallScore" do
    field :avg_pass, :float
    field :avg_fail, :float
    field :total_students, :float
    embeds_many :my_score_schema, MyScoreSchema
  end
  @required_fields ~w[]a
  @optional_fields ~w[avg_pass, avg_fail, total_students ]a


  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @optional_fields, required: false )
    |> cast_embed(:my_score_schema, required: false)
  end
end

并拥有一个http://localhost:8080/getScoreData提供数据的 HTTP REST API

{
      "avgPass": 85.55,
      "avgFail": 14.45,
      "totalStudents": 80.0,
      "myScoreSchema": [
        {
          "average": 80.0,
          "count": 8.0,
          "percent": 80.0,
          "name": "John"
        },
        {
          "average": 90.0,
          "count": 8.0,
          "percent": 90.0,
          "name": "Cena"
        },
        {
          "average": 80.0,
          "count": 8.0,
          "percent": 80.0,
          "name": "Sunny"
        },
        {
          "average": 70.0,
          "count": 8.0,
          "percent": 70.0,
          "name": "Michael"
        }
      ]
    }

和代码

  url = "http://localhost:8080/getScoreData"
   Logger.info("the url is #{url}")
   case HTTPoison.get(url) do
     {:ok, %{status_code: 200, body: body}} ->
       overall_score = Jason.decode!(body, as: [%OverallScore{}])
       {:ok, overall_score}
   end

这以某种方式起作用并且不会给出错误,但结果是一些struct而不是真的OverallScore ecto schema object

标签: jsonelixirectoelixir-poisonhttpoison

解决方案


我建议不要使用“as:[%OverallScore{}]”语法,而是使用模型中已有的变更集。这看起来像这样:

  url = "http://localhost:8080/getScoreData"
   Logger.info("the url is #{url}")
   case HTTPoison.get(url) do
     {:ok, %{status_code: 200, body: body}} ->
       response = Jason.decode!(body)
       overall_score = OverallScore.changeset(%OverallScore{}, response)
       {:ok, overall_score}
   end

变更集通常是将对象放入 ecto 结构的最佳方式,因为它们将正确运行您的变更集验证。这有一个额外的好处,它会在“响应”字段中删除它不在变更集的强制转换调用中的任何内容,而不会出现任何错误。您还可以快速检查它是否有效,如果有效,您可以使用 ecto repo 将其插入数据库。


推荐阅读