Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ config :logger, :console,
format: "\n$time $metadata[$level] $message\n"

config :phoenix,
json_library: Jason,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably here we would need to have something similar to if Code.ensure_loaded?(JSON), do: JSON, else: Jason if that conditional loading trick makes sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it does and yes, we definitely need it (and also adjust the tests to assert the correct errors in CI)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, for sure. I wasn't certain if the said approach (determining JSON availability by Code.ensure_loaded?) is the correct one. But if it will do, then yes, I'll update the tests

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can wait for José to chime in. Sometimes you need Code.ensure_compiled, but I think for a built in module ensure_loaded should be fine?

# TODO: Remove the `json_library` check once `JSON` becomes the standard `Phoenix.json_library/1`
json_library: (if Code.ensure_loaded?(JSON), do: JSON, else: Jason),
stacktrace_depth: 20,
trim_on_html_eex_engine: false

Expand Down
2 changes: 1 addition & 1 deletion guides/controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ end

Now [`/hello/Frank`] in your browser should display `From messenger Frank` as plain text without any HTML.

A step beyond this is rendering pure JSON with the [`json/2`] function. We need to pass it something that the [Jason library](`Jason`) can decode into JSON, such as a map. (Jason is one of Phoenix's dependencies.)
A step beyond this is rendering pure JSON with the [`json/2`] function. We need to pass it something that the [JSON library](https://hexdocs.pm/elixir/JSON.html) can decode into JSON, such as a map.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's how it looks like with mouse hover:

Image


```elixir
def show(conn, %{"messenger" => messenger}) do
Expand Down
2 changes: 1 addition & 1 deletion guides/json_and_apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ defmodule HelloWeb.UrlJSON do
end
```

This view is very simple. The `index` function receives all URLs, and converts them into a list of maps. Those maps are placed inside the data key at the root, exactly as we saw when interfacing with our application from `cURL`. In other words, our JSON view converts our complex data into simple Elixir data-structures. Once our view layer returns, Phoenix uses the `Jason` library to encode JSON and send the response to the client.
This view is very simple. The `index` function receives all URLs, and converts them into a list of maps. Those maps are placed inside the data key at the root, exactly as we saw when interfacing with our application from `cURL`. In other words, our JSON view converts our complex data into simple Elixir data-structures. Once our view layer returns, Phoenix uses the built-in [JSON library](https://hexdocs.pm/elixir/1.18/JSON.html) to encode JSON and send the response to the client.

If you explore the remaining controller, you will learn the `show` action is similar to the `index` one. For `create`, `update`, and `delete` actions, Phoenix uses one other important feature, called "Action fallback".

Expand Down
2 changes: 1 addition & 1 deletion guides/plug.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ The default endpoint plugs do quite a lot of work. Here they are in order:

- `Plug.Telemetry` - adds instrumentation points so Phoenix can log the request path, status code and request time by default.

- `Plug.Parsers` - parses the request body when a known parser is available. By default, this plug can handle URL-encoded, multipart and JSON content (with `Jason`). The request body is left untouched if the request content-type cannot be parsed.
- `Plug.Parsers` - parses the request body when a known parser is available. By default, this plug can handle URL-encoded, multipart and JSON content. The request body is left untouched if the request content-type cannot be parsed.

- `Plug.MethodOverride` - converts the request method to PUT, PATCH or DELETE for POST requests with a valid `_method` parameter.

Expand Down
4 changes: 2 additions & 2 deletions installer/templates/phx_single/config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ config :logger, :default_formatter,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]

# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Use built-in `JSON` for JSON parsing in Phoenix
config :phoenix, :json_library, JSON

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
Expand Down
4 changes: 2 additions & 2 deletions installer/templates/phx_umbrella/config/extra_config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ config :logger, :default_formatter,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]

# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Use built-in `JSON` for JSON parsing in Phoenix
config :phoenix, :json_library, JSON

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
Expand Down
2 changes: 1 addition & 1 deletion installer/test/phx_new_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ defmodule Mix.Tasks.Phx.NewTest do
assert_file("phx_blog/config/config.exs", fn file ->
assert file =~ "ecto_repos: [PhxBlog.Repo]"
assert file =~ "generators: [timestamp_type: :utc_datetime]"
assert file =~ "config :phoenix, :json_library, Jason"
assert file =~ "config :phoenix, :json_library, JSON"
assert file =~ ~s[cd: Path.expand("../assets", __DIR__),]
refute file =~ "namespace: PhxBlog"
refute file =~ "config :phx_blog, :generators"
Expand Down
2 changes: 1 addition & 1 deletion installer/test/phx_new_umbrella_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ defmodule Mix.Tasks.Phx.New.UmbrellaTest do
assert file =~ ~r/config :esbuild/
assert file =~ "cd: Path.expand(\"../apps/phx_umb_web/assets\", __DIR__)"
assert file =~ ~S[import_config "#{config_env()}.exs"]
assert file =~ "config :phoenix, :json_library, Jason"
assert file =~ "config :phoenix, :json_library, JSON"
assert file =~ "ecto_repos: [PhxUmb.Repo]"
assert file =~ ":phx_umb_web, PhxUmbWeb.Endpoint"
assert file =~ "generators: [context_app: :phx_umb]\n"
Expand Down
3 changes: 2 additions & 1 deletion integration_test/config/config.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Config

config :phoenix, :json_library, Jason
# TODO: Remove the `json_library` check once `JSON` becomes the standard `Phoenix.json_library/1`
config :phoenix, :json_library, (if Code.ensure_loaded?(JSON), do: JSON, else: Jason)

config :swoosh, api_client: false

Expand Down
1 change: 1 addition & 0 deletions lib/phoenix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ defmodule Phoenix do

"""
def json_library do
# TODO: Change the default json library to JSON in Phoenix v2.0
Application.get_env(:phoenix, :json_library, Jason)
end

Expand Down
6 changes: 3 additions & 3 deletions test/phoenix/socket/v1_json_serializer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defmodule Phoenix.Socket.V1.JSONSerializerTest do
msg = %Message{topic: "t", event: "e", payload: "m"}
encoded = encode!(@serializer, msg)

assert Jason.decode!(encoded) == %{
assert Phoenix.json_library().decode!(encoded) == %{
"event" => "e",
"payload" => "m",
"ref" => nil,
Expand All @@ -36,7 +36,7 @@ defmodule Phoenix.Socket.V1.JSONSerializerTest do
msg = %Reply{topic: "t", ref: "null"}
encoded = encode!(@serializer, msg)

assert Jason.decode!(encoded) == %{
assert Phoenix.json_library().decode!(encoded) == %{
"event" => "phx_reply",
"payload" => %{"response" => nil, "status" => nil},
"ref" => "null",
Expand All @@ -61,7 +61,7 @@ defmodule Phoenix.Socket.V1.JSONSerializerTest do
msg = %Broadcast{topic: "t", event: "e", payload: "m"}
encoded = fastlane!(@serializer, msg)

assert Jason.decode!(encoded) == %{
assert Phoenix.json_library().decode!(encoded) == %{
"event" => "e",
"payload" => "m",
"ref" => nil,
Expand Down
2 changes: 1 addition & 1 deletion test/phoenix/socket/v2_json_serializer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ defmodule Phoenix.Socket.V2.JSONSerializerTest do
msg = %Reply{topic: "t", payload: %{m: 1}}
encoded = encode!(@serializer, msg)

assert Jason.decode!(encoded) == [
assert Phoenix.json_library().decode!(encoded) == [
nil,
nil,
"t",
Expand Down
12 changes: 9 additions & 3 deletions test/phoenix/test/conn_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,19 @@ defmodule Phoenix.Test.ConnTest do
build_conn(:get, "/") |> resp(200, "ok") |> json_response(200)
end

assert_raise Jason.DecodeError,
"unexpected byte at position 0: 0x6F (\"o\")", fn ->
json_error =
case Phoenix.json_library() do
JSON -> JSON.DecodeError
Jason -> Jason.DecodeError
end

assert_raise json_error,
~r/invalid byte 111 at position \(byte offset\) 0|unexpected byte at position 0: 0x6F \("o"\)/, fn ->
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the most elegant solution, but...

Image

build_conn(:get, "/") |> put_resp_content_type("application/json")
|> resp(200, "ok") |> json_response(200)
end

assert_raise Jason.DecodeError, ~r/unexpected end of input at position 0/, fn ->
assert_raise json_error, ~r/unexpected end of JSON binary at position \(byte offset\) 0|unexpected end of input at position 0/, fn ->
build_conn(:get, "/")
|> put_resp_content_type("application/json")
|> resp(200, "")
Expand Down
Loading