How to enforce JSON encoding for Phoenix Request?

孤者浪人 提交于 2020-02-27 23:42:27

问题


There's some API made with Phoenix, the API works with JSON.

But, when you test it and sent JSON with curl it fail because Phoenix doesn't parse the request as JSON. You need to explicitly add application/json header to curl. I'd like to make it more robust and tell Phoenix to always parse all requests as JSON.

Is there a way to force Phoenix to always treat requests as JSON and parse it as JSON?

UPDATE

I tried to use 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

The request has been made with CURL

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

The connection looks like:

%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 to CURL, without it it doesn't work.


回答1:


If somebody will google for that and want to implement such behaviour.

lib/%APP_NAME%/endpoint.ex

 plug Plug.Head

 # add custom plug 
 plug :set_format, "json"

Define it:

  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 dirty hack which will enforce JSON format for subdomain api

It's not recommended to do like that but since Phoenix enforcing HTML at any time this hack fix ridiculous behaviour like: Elixir.Phoenix.Router.NoRouteError for pipeline :api to show 404.json instead of 404.html



来源:https://stackoverflow.com/questions/38185875/how-to-enforce-json-encoding-for-phoenix-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!