【问题标题】:How to render a JSON file with the Phoenix framework?如何使用 Phoenix 框架渲染 JSON 文件?
【发布时间】:2017-04-29 16:17:21
【问题描述】:

我想使用手动编写的 JSON 文件作为数据,而不是从数据库中获取数据。假设我的数据是这样的:

[
    { "id": 1, "name": "Alice", "email": "alice@example.com" },
    { "id": 2, "name": "Bob", "email": "bob@example" },
    { "id": 3, "name": "Charles", "email": "charles@example.com"}
]

它写在一个名为MOCK_DATA.json 的文件中。当我访问localhost:port/api/v1/users url 时,我应该怎么做才能呈现这个文件?显示{ "id": 1, "name": "Alice", "email": "alice@example.com" }localhost:port/api/v1/users/1 网址怎么样?

【问题讨论】:

  • 所以您只是想模拟响应以快速开始,然后用“真实”实现替换它?我猜这不一定要准备好生产?
  • @PatrickOscity 是的,完全正确。

标签: json elixir phoenix-framework


【解决方案1】:

这是一个基本的工作示例......

第 1 步:创建凤凰应用程序

例如,Exjson for ExampleJson 或任何你喜欢的名字

mix phoenix.new exjson --no-ecto --no-brunch --no-html
第二步:设置路由器

将此作用域添加到 web/router.ex 文件中

  scope "/api/v1", Exjson do
    pipe_through :api
    resources "/users", UserController
  end
第 3 步:将模拟数据放在应用程序可访问的位置
priv/data/MOCK_DATA.json
第 4 步:设置用户控制器

将用户控制器视为具有许多操作(功能) conn struct 从您的凤凰端点与任何 参数

defmodule Exjson.UserController do
  use Exjson.Web, :controller

  # GET http://localhost:4000/api/v1/users/
  def index(conn, _params) do
    users = File.read!(file) |> Poison.decode!()
    render conn, users: users
  end

  # GET http://localhost:4000/api/v1/users/1
  def show(conn, params) do
    users = File.read!(file) |> Poison.decode!()
    render conn, user: users |> Enum.find(&(&1["id"] === String.to_integer(params["id"])))
  end

  defp file() do
    Path.join(:code.priv_dir(:exjson), "data/MOCK_DATA.json")
  end

end
第 5 步:设置用户视图

您还可以将用户视图视为具有以适当方式呈现从控制器接收的数据的功能。在这种情况下,您使用的是 json 数据,因此 phoenix 有一些内置函数来帮助解决这个问题。

defmodule Exjson.UserView do
  use Exjson.Web, :view

  def render("index.json", %{users: users}) do
    render_many(users, __MODULE__, "user.json")
  end

  def render("show.json", %{user: user}) do
    render_one(user, __MODULE__, "user.json")
  end

  def render("user.json", %{user: user}) do
    %{
      id: user["id"],
      name: user["name"],
      email: user["email"]
    }
  end

end

【讨论】:

  • 如果您只是在您的 api 中发送 json,那么就在浏览器上呈现数据而言,如今,开发人员通常使用所谓的“单页应用程序”框架来创建用户界面(浏览器组件) .例如AureliaAngular2 但仅举几例,还有很多......
  • Path.join函数中的:code.priv_dir(:exjson)参数是什么?我搜索了 phoenix 源代码,但搜索结果为空。
  • 这是来自erlang library.. 的函数。它只是获取您的 priv 文件夹。此文件夹中的文件可供应用程序使用。
  • 注意如果这对其他人有帮助,我必须将最后一个渲染函数更改为使用%{users: user}(用户与用户),但我对此仍然很陌生,我可能不理解某些东西。
【解决方案2】:

为了给你一些真正的代码来开始,这是我能想到的最简单的事情:

defmodule MyApp.UserController do
  @mock_data (
    Application.app_dir(:my_app, "priv/mock_data/users.json")
    |> File.read!
    |> Poison.decode!
  )

  def index(conn, _params) do
    conn
    |> put_status(:ok)
    |> json(@mock_data)
  end
end

然后将您的假数据保存在项目中的priv/mock_data/users.json 中。那里可能有错别字,但你明白基本的想法......

【讨论】:

    【解决方案3】:

    由于您只是为 /users 端点回显 JSON,在这种情况下,您不需要对 JSON 进行不必要的解码/编码的 Poison.decode/1 调用。

    所以,改编帕特里克的代码:

    defmodule MyApp.UserController do
      @mock_data_string (
        Application.app_dir(:my_app, "priv/mock_data/users.json")
        |> File.read!
      )
    
      def index(conn, _params) do
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(200, @mock_data_string)
      end
    end
    

    但是,对于/users/1 端点,最好使用Poison.decode/1 提取值,如@stephen_m 的回答所示。

    【讨论】:

    • 太好了!我只是需要类似的东西(只是通过 Phoenix 从另一台服务器转发 JSON 数据)。我试试看!
    【解决方案4】:

    如果文件是静态文件(在服务运行过程中不会更改),那么您可以在应用程序在您的控制器中编译时读取它。查看模块参数(您在模块中定义的那些,在函数之外)。这样我就会被解析一次。

    如果这个文件是动态的,那么你可能需要在每次调用 API 时读取它并解析它。不建议这样做,因为从磁盘 IO 读取文件会减慢速度。

    在任何情况下,解析为 Map 的文件结果都可以传入视图并渲染,与数据库没有区别。

    编辑:另一个建议是重新格式化您的 JSON(如果可能)并将 id 作为键,将其余数据作为值。这样id 的查找速度会非常快,就像数据库中的主键索引一样。

    【讨论】:

    • 我是 Phoenix 和 Elixir 的初学者,所以我不明白你的答案。你能给我一些代码示例吗?另外,感谢您的性能提示,但目前我什至不知道如何在浏览器上呈现数据,因此我希望能提供有关该区域的具体说明。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    • 2016-07-18
    相关资源
    最近更新 更多