I originally forgot to mention that my
MainPlug is a
Plug.Router. I only realized it while responding to Overmind, below. I’ve now updated the initial message to make it clear.
I’m working on a project where I have a main Plug that acts as the public API of the library. This module is a
Plug.Router and it includes its own plug pipeline. Users are supposed to use it in their routers and forward traffic to it. Let’s call it
This main plug router then uses a number of child plugs to get some work done. These must be separate plugs, because the idea is that users can still use these building blocks to create their own router, if they need some custom logic.
My problem is that I can’t find a way to forward options to the nested “child” plugs.
For example, this is my Phoenix router, where I forward to my plug and pass some options to it:
defmodule MyPhoenixApp.Web.Router do use MyPhoenixApp.Web, :router pipeline :api do plug :accepts, ["json"] end scope path: "/stuff" do pipe_through :api forward "/", MyPackage.MainPlug, my_options: [foo: "foo", bar: "bar"] end end
In the next snippet are my main plug (first) and the child plug (second):
defmodule MyPackage.MainPlug do use Plug.Router plug MyPackage.ChildPlug def init(opts) do opts # == [my_options: [foo: "foo", bar: "bar"]] end def call(conn, opts) do # opts == [my_options: [foo: "foo", bar: "bar"]] conn = Plug.Conn.assign(conn, :my_options, opts[:my_options]) # do more stuff with conn end end defmodule MyPackage.ChildPlug do def init(opts) do opts # ==  end def call(conn, opts) do # I need the extra options here! conn end end
My problem is that I want to be able to customize
ChildPlug from the outside, but I can’t find a clear way to do it.
As you can see, in
MainPlug.call/2 I’m assigning the options to the
conn just as an example, but it doesn’t really help me because, by then,
ChildPlug has already been run.
I guess I could avoid the
plug macro and invoke the child plugs directly in
MainPlug.call/2, for example:
defmodule MyPackage.MainPlug do use Plug.Router alias MyPackage.PrivatePlug def init(opts) do opts # == [my_options: [foo: "foo", bar: "bar"]] end def call(conn, opts) do conn = PrivatePlug.call(conn, PrivatePlug.init(opts)) # do more stuff with conn end end
That would work, but I’d lose the nice performance gain of being able to manipulate the
opts in the
init function ahead of time.
Also, this seems a common enough requirement that hopefully there is already a clean API to do what I need.