2016-07-04 10 views
6

There's some API wykonane z Phoenix, API współpracuje z JSON.Jak wymusić kodowanie JSON dla żądania Phoenix?

Ale kiedy przetestujesz i wysłałeś JSON z curl, to się nie uda, ponieważ Phoenix nie analizuje żądania jako JSON. Musisz jawnie dodać nagłówek application/json do curl. Chciałbym sprawić, by był bardziej solidny i powiedzieć Phoenixowi, aby zawsze analizował wszystkie żądania jako JSON.

Czy istnieje sposób zmuszenia Phoenixa do traktowania wniosków jako JSON i analizowania go jako JSON?

UPDATE

Próbowałem użyć wtyczki ustawić nagłówki żądania jak sugeruje @AbM, z następującego kodu w routerze:

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 

kupna została wykonana z zwinięcie

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

Połączenie wygląda następująco:

%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} 

Działa, jeśli dodaję parametr -H "Content-Type: application/json" do CURL, bez niego to nie zadziała.

+0

Dodałbym wtyczkę do twojego routera za pomocą ['put_req_header (conn," accept "," application/json ")' ] (https://hexdocs.pm/plug/Plug.Conn.html#put_req_header/3) rozwiązać swój problem? – AbM

+0

Nie, to nie działa :( –

+0

Czy możesz rozwinąć nieco więcej.Może pokazać swój router.ex – AbM

Odpowiedz

1

Jeśli ktoś będzie google do tego i chcesz wdrożyć takie zachowanie.

lib/%APP_NAME%/endpoint.ex

plug Plug.Head 

# add custom plug 
plug :set_format, "json" 

Zdefiniuj go:

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 

W tym przykładzie mamy brudną siekać który będzie wymuszał formatu JSON dla subdomeny api

Nie zaleca zrobić tak ale odkąd Phoenix wymusza HTML w dowolnym momencie, ten hack naprawia niedorzeczne zachowanie ur jak: Elixir.Phoenix.Router.NoRouteError dla pipeline :api, aby wyświetlić 404.json zamiast 404.html

Powiązane problemy