如何使用Phoenix框架呈现JSON文件?

时间:2016-01-26 21:48:23

标签: json elixir phoenix-framework

我希望将数据用作手动编写的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网址时,我该怎么做才能呈现此文件? localhost:port/api/v1/users/1显示{ "id": 1, "name": "Alice", "email": "alice@example.com" }的网址怎么样?

4 个答案:

答案 0 :(得分:9)

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

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

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

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

将此范围添加到web / router.ex文件

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

将用户控制器视为具有多个操作(功能) 其中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步:设置UsersView

您还可以将用户视图视为具有以适当方式呈现从Controller接收的数据的功能。在这种情况下,您使用的是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

答案 1 :(得分:9)

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

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中。那里可能有拼写错误,但你得到的基本想法......

答案 2 :(得分:3)

由于您只是回复了/users端点的JSON,因此您不需要Poison.decode/1调用,这会对JSON进行不必要的解码/编码。

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

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的答案所示。

答案 3 :(得分:1)

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

如果此文件是动态的,那么每次调用API时都需要读取它并解析它。没有真正建议,因为从磁盘IO读取文件会降低速度。

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

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