简体   繁体   English

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

[英]How to render a JSON file with the Phoenix framework?

Instead of fetching data from a database, I want to use as data a manually written JSON file. 我想将数据用作手动编写的JSON文件,而不是从数据库中获取数据。 Suppose my data is this: 假设我的数据是这样的:

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

and it's written in a file called MOCK_DATA.json . 它写在一个名为MOCK_DATA.json的文件中。 What should I do to render this file when I access the localhost:port/api/v1/users url? 当我访问localhost:port/api/v1/users时,我该怎么做才能呈现这个文件localhost:port/api/v1/users url? How about the localhost:port/api/v1/users/1 url to show { "id": 1, "name": "Alice", "email": "alice@example.com" } ? localhost:port/api/v1/users/1 url如何显示{ "id": 1, "name": "Alice", "email": "alice@example.com" }

Here is a basic working example... 这是一个基本的工作示例......

Step 1: Create the phoenix app 第1步:创建凤凰应用程序

eg, exjson for ExampleJson or whatever name your like 例如,exjson用于ExampleJson或任何你喜欢的名字

  scope "/api/v1", Exjson do
    pipe_through :api
    resources "/users", UserController
  end
Step 2: Set up the router 第2步:设置路由器

Add this scope to the web/router.ex file 将此范围添加到web / router.ex文件中

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

Think of the Users Controller as having a number of actions (functions) where the conn struct is fed into from your phoenix endpoint along with any parameters 可以将用户控制器视为具有许多动作(函数),其中conn struct从您的phoenix端点以及任何参数输入

 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 
Step 5: Set up the UsersView 第5步:设置UsersView

You can also think of the Users View as having functions that will render the data received from the Controller in the appropriate way. 您还可以将“用户视图”视为具有以适当方式呈现从Controller接收的数据的功能。 In this case, you are using json data so phoenix has some built in functions to help with that. 在这种情况下,您正在使用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 

To give you some real code to get started, this is the simplest thing I can think of: 为了给你一些真正的代码来开始,这是我能想到的最简单的事情:

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

Then just save your fake data in priv/mock_data/users.json inside your project. 然后将您的假数据保存在项目内的priv/mock_data/users.json There might be typos in there, but you get the basic idea... 那里可能有拼写错误,但你得到的基本想法......

Since you're just echoing the JSON back for the /users endpoint, in that case you don't need the Poison.decode/1 call which does unnecessary decoding/encoding of the JSON. 由于您只是为/users端点回显JSON,在这种情况下,您不需要Poison.decode/1调用,它会对JSON进行不必要的解码/编码。

So, adapting Patrick's code: 所以,调整Patrick的代码:

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

However, for the /users/1 endpoint, it is best to extract values by using Poison.decode/1 , as @stephen_m's answer illustrates. 但是,对于/users/1端点,最好使用Poison.decode/1提取值,如@ stephen_m的答案所示。

If the file is static (does not change for the course of the service running) then you can read it when the app compiles in your controller. 如果文件是静态的(在服务运行过程中没有改变),那么当应用程序在您的控制器中编译时,您可以读取它。 Look into module parameters (the ones you define in your module, outside of functions). 查看模块参数(您在模块中定义的参数,在函数之外)。 This way i'll be parsed once. 这样我将被解析一次。

If this file is dynamic then you may need to read it every time the API is called and parse it. 如果此文件是动态的,那么您可能需要在每次调用API时读取它并对其进行解析。 Not really advised since reading a file from disk IO will slow it down. 没有真正建议,因为从磁盘IO读取文件会降低速度。

In any case the result of the file, parsed to a Map can then be passed in into the view and rendered, no difference from the database. 在任何情况下,解析到Map的文件结果都可以传入视图并呈现,与数据库没有区别。

Edit: another suggestion is to reformat your JSON (if possible) and have id as a key and the rest of the data as a value. 编辑:另一个建议是重新格式化您的JSON(如果可能)并将id作为键,其余数据作为值。 This way lookups by id will be very fast, just like a primary key index in the database. 这样, id查找速度非常快,就像数据库中的主键索引一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM