AntonFagerberg / rackla

Open Source API Gateway in Elixir

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proxy HTTP Response Code, Too?

djthread opened this issue · comments

Hello, Anton!

I am hoping to make use of Rackla for a project, but despite sinking some time into it, I seem unable to relay the HTTP headers or response code. (The response body is being relayed properly.)

I'm a little confused because I would have thought that the default behavior for an HTTP proxy like this would be to forward the whole response, as constructed by the application web server.

I've got a simple routine like the following:

  get "/test" do
    "http://example.com"
    |> request
    |> response
  end

It seems that the response function

  • Responds to the client with the 200 response code and the basic Cowboy headers
  • Fires the request to example.com
  • Proxies the response body from the proxied app to the client's response

It's not even obvious how I would split this up... It seems I want to call example.com, THEN fill out the client response?

Doesn't it make sense that I would want to preserve the code & headers from the app when proxying with Rackla? I would love a hint as to why my expectation is wrong and/or how I might accomplish this with Rackla.

In any case, thank you for sharing your work on this library! I very much appreciated finding it.

Thank you!!

Adam

Hey!

Thanks for you kind words, I appreciate them 😃

This is a bit tricky since Rackla was mainly developed with the purpose of being able to combine multiple responses (with different headers and response codes) and start transmitting asynchronously to the client before all responses has arrived to the proxy. This, among other things, made doing the "happy flow" easy but passing along headers and status code is trickier - I'm not sure this was the best approach but that's the history.

Anyway, you can still achieve what you're trying to do, just not as pretty.

I haven't tested this code but this is basically what you want to do:

%Rackla.Response{status: status, headers: headers, body: body} =
  "http://example.com"
  |> request(full: true) # Set to true to get %Rackla.Response{} and not just body
  |> collect # Await the response and turn it in to a local structure

just(body) # Turn body back into async "Rackla type"
|> response(status: status, headers: headers) # create response and add status and headers as options

Makes sense? Otherwise let me know and I'll try to make a better explanation!

Thank you so much for that. I did sort of figure I was working a bit against the grain of your tool with what I'm doing. My requirements are pretty simple, so I'm now thinking I might just go with straight Plug & HTTPoison to do what I need, looking to rackla later if I need to tackle the same problems you have overcome.

I did want to give your example a try, though, btw. I hit an error, it seems, as rackla.ex:119 attempts to pattern match on the hackney's return. It seems you were expecting a fourth tuple element with the body, but I don't seem to have one! I'm on hackney 1.6 as you required... not sure why.

12:57:08.429 [error] Task #PID<0.321.0> started from #PID<0.320.0> terminating
** (CaseClauseError) no case clause matching: {:ok, 200, [{"Server", "nginx"}, {"Date", "Wed, 01 Mar 2017 17:57:08 GMT"}, {"Content-Type", "text/html; charset=UTF-8"}, ...]}
    (rackla) lib/rackla.ex:119: anonymous fn/2 in Rackla.request/2
    (elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Function: #Function<22.59910976/0 in Rackla.request/2>
    Args: []

That's strange, I tried running my example and it worked without any modifications. If you get an error on line 119 then that's inside the request function so perhaps you have changed or mixed up something from my example?

Otherwise I agree that it's probably easier for your use case to just use plug and httpoison for this simple use case 👍

Cheers for that. Thanks again for your help, Anton.