I'm trying to create a very simple case: a controller action which renders a static JSON, from a template.
controller:
defmodule MyApp.TestController do
use Phoenix.Controller
def show(conn, _params) do
render(conn, "show.json")
end
end
view:
defmodule MyApp.TestView do
use MyApp.Web, :view
end
show.json.eex
:
{
"message": "Hello, world!"
}
The problem is, I get the proper JSON response, but JSON-encoded:
"{\n \"message\": \"Hello, world!\"\n}"
Any idea why, and how to solve it?
/Edit:
I found out that I can work around the problem by renaming the template to something other than json
(plus explicitly setting response type, of course), so obviously JSON templates are additionally encoded. But why, who would want such a thing?
After further investigation and talking with people on Phoenix Slack channel, I have a clearer picture about what's going on:
Phoenix is agnostic when it comes to deciding whether the content comes from a template or from a data structure in the view. render/2
from the controller happily takes anything and converts it to JSON.
I wrote up a more detailed blog post about this issue, along with several approaches in addressing it, and in my opinion every is a workaround for the inherent problem in Phoenix (which, admittedly, is far from critical).
Essentially, one should avoid executing Poison.encode
function, which gets called from render_to_iostream
function. You can do that either by not using .json
as the template extension, by directly calling Phoenix.View.render
from the controller, or by creating custom encoder and template engine to pass some metadata along with the data to be output.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With