Action-Specific Plug Pipelines for Phoenix

13 Feb 20

For our APIs, most of our actions need a common set of plugs (Elixir's middleware). Phoenix has the concept of pipelines, which are a sequence of plugs you can apply to a group of routes. But our actions tend to need action-specific configuraiton.

The way to do this in Phoenix is via the plug macro with a guard clause on your aciton:

plug App.Plugs.Context, [route: "user_list"] when action == :index
plug App.Plugs.Cache, [:public, ttl: 60] when action == :index
plug App.Plugs.Validate, [
search: [string: [max: 50]],
page: [:int, default: 1]
] when action == :index

It's a mouthful! But with a bit of code, we can turn the above into:

pipeline :index, [
context: [route: "user_list"],
cache: [:public, ttl: 60],
validate: [
search: [string: [max: 50]],
page: [:int, default: 1]

pipeline/2 is just a macro that converts this improved version into the original:

defmacro pipeline(action, plugs) do
for {plug, config} <- plugs do
plug = case plug do
:context -> App.Plugs.Context
:cache -> App.Plugs.Cache
:validate -> App.Plugs.Validate

quote location: :keep do
plug unquote(plug), unquote(config) when var!(action) == unquote(action)

I hope someone finds that useful.