How to provide JSON encoding for a Phoenix request?

Where the API works with Phoenix, the API works with JSON.

But, when you test it and send JSON with curl , it fails because Phoenix does not parse the request as JSON. You need to explicitly add the application/json header in curl . I would like to make it more reliable and tell Phoenix to always parse all requests as JSON.

Is there a way to get Phoenix to always process requests as JSON and parse it as JSON?

UPDATE

I tried using a plug to set request headers, as @AbM suggested, with the following code in Router:

 def set_format conn, format do Plug.Conn.put_private conn, :phoenix_format, format end def put_req_header conn, {key, value} do Plug.Conn.put_req_header conn, key, value end pipeline :api do plug :put_req_header, {"accept", "application/json"} plug :put_req_header, {"content-type", "application/json"} plug :set_format, "json" plug :accepts, ["json"] end 

Request completed with CURL

 curl -X POST http://localhost:4000/api/upload -d '{"key": "value"}' 

The connection looks like this:

 %Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{}, before_send: [#Function<1.93474994/1 in Plug.Logger.call/2>, #Function<0.119481890/1 in Phoenix.LiveReloader.before_send_inject_reloader/1>], body_params: %{"{\"key\": \"value\"}" => nil}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "localhost", method: "POST", owner: #PID<0.483.0>, params: %{"{\"key\": \"value\"}" => nil}, path_info: ["api", "upload"], peer: {{127, 0, 0, 1}, 58408}, port: 4000, private: %{App.Router => {[], %{}}, :phoenix_action => :upload, :phoenix_controller => ApiController, :phoenix_endpoint => App.Endpoint, :phoenix_format => "json", :phoenix_layout => {LayoutView, :app}, :phoenix_pipelines => [:api], :phoenix_route => #Function<8.59735990/1 in App.Router.match_route/4>, :phoenix_router => App.Router, :phoenix_view => ApiView, :plug_session_fetch => #Function<1.89562996/1 in Plug.Session.fetch_session/1>}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %Plug.Conn.Unfetched{aspect: :cookies}, req_headers: [{"user-agent", "curl/7.37.1"}, {"host", "localhost:4000"}, {"accept", "application/json"}, {"content-length", "16"}, {"content-type", "application/json"}], request_path: "/api/upload", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "xxx"}], scheme: :http, script_name: [], secret_key_base: "xxx", state: :unset, status: nil} 

It works if I add the -H "Content-Type: application/json" parameter -H "Content-Type: application/json" to CURL, it does not work without it.

+6
source share
1 answer

If someone will google for this and want to implement this behavior.

lib/%APP_NAME%/endpoint.ex

  plug Plug.Head # add custom plug plug :set_format, "json" 

Define this:

  defp set_format(conn, format) do if Regex.match?(~r/^api.*/, conn.host) do Plug.Conn.put_private conn, :phoenix_format, format else conn end end 

In this example, we have a dirty hack that will provide the JSON format for the api subdomain

It is not recommended to do this, but since Phoenix applies HTML at any time, this hack fixes funny behavior, for example: Elixir.Phoenix.Router.NoRouteError for pipeline :api to display 404.json instead of 404.html

+1
source

All Articles