AntonFagerberg / rackla

Open Source API Gateway in Elixir

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

POST/PUT/PATCH

beno opened this issue · comments

commented

What is the best way to handle requests with payloads? I can't figure out how to access the request body and pass it on.

Related question: is it possible to basically clone an incoming request, modify some aspects (like the host and path) of it and then execute that?

Rackla is built using Plug so everything you can do in Plug, you can also do in Rackla. You can either use the Plug.Conn.read_body/2 or you can use Plug.Parsers if you want to do more complex things.

Example:

{:ok, body, conn} = Plug.Conn.read_body(conn)

It is not possible to convert an incoming "Plug request" to a "Rackla request", but that would actually be a really good feature. I will look into that!

commented

Great, thanks, I got it working. I knew there was a way, but my Elixir-fu just isn't all that great.

To be honest, I was fully expecting that request-proxy trick to be the core feature of an API-Gateway framework like Rackla. So I am glad you are looking into it! Thanks again.

Edit: FYI, here's how I ended up solving it:

defmodule Router do

  use Plug.Router
  import Rackla

  plug :match
  plug :dispatch

  defp proxy(url, conn) do
    method = conn.method |> String.downcase |> String.to_atom
    {:ok, body, _conn} = Plug.Conn.read_body(conn)
    %Rackla.Request{url: url, method: method, body: body, headers: conn.req_headers}
    |> request
    |> response
  end

  match "/admin/*path" do
    "http://admin.example.com:9292/v1/#{Enum.join(path,"/")}"
    |> proxy(conn)
  end

  match _ do
   send_resp(conn, 404, "Endpoint not found")
  end

end

Nice solution!

You should always reassign conn to the new conn returned by the function and not do _conn. (It will probably work anyway but this is the desired practice.)

As of version 1.1.0, you can now use the built in function incoming_request:

get "/test/a-simple-request-proxy" do
  # You should check for errors
  {:ok, the_request} = incoming_request()

  the_request
  |> Map.put(:url, "http://new-url.com")
  |> request
  |> response
end

Look for the macro incoming_requestin the documentation!

commented

O that is sweet. Thanks!

commented

Hi, I hadn't had a chance to implement this yet, but I now have and there are two issues I'd like to report:

  • When I write the code as above, I run into a compilation error

** (CompileError) lib/deal_manager.ex: invalid quoted expression: %{}
(rackla) expanding macro: Rackla.incoming_request/0

I can get around this by calling incoming_request(%{}).

  • The incoming request loses the query_string. Can't have that 😄
    Not a real issue form me since I rewrite the url, but still.

Other than that it all seems to work, but I haven't done all my tests yet.

Thanks for the report! I'll fix these issues as soon as possible :)

Fixed in 1.2.1! (See #25)