2

Background

I have a simple Plug router that has some POST, PUT and GET endpoints. However, each endpoint needs to make a specific validation on the headers of the request. I don’t know how to achieve this with Plug. Code

I have a very generic router that receives requests and redirects them to controllers:

defmodule Api do
  use Plug.Router

  alias Api.Controllers.{Product, NotFound, Ping}

  plug :match
  plug Plug.Logger
  plug :dispatch

  get "/ping",  do: Ping.process(conn)
  put "/product",    do: Product.process(conn)

  match _, do: NotFound.process(conn)
end

Issue

However, there is a step missing. I need for the /products endpoint to validate the headers. Namely the headers should have some specific fields set, for example, like the “conten-type” header or even a custom header like “bananas”.

This validation is NOT for all endpoints. What makes it worse is that each endpoint will make its own validations, for example, having a “bananas” header may be important for the “/products” endpoint, but the “/ping” endpoint doesn’t really care.

Research

I have read this article:

However, this applies to all endpoints and is not specific.

Questions

  • Is it possible to achieve what I am looking for with Plug? If so, how?
Flame_Phoenix
  • 16,489
  • 37
  • 131
  • 266

1 Answers1

1

You can do anything you want in the do block for the paths in plug. I sometimes use an around filter pattern for things like this. Something like:

defmodule Api do
  use Plug.Router

  # ...

  put "/product"  do
    with_valid_headers(conn, fn ->
      Product.process(conn)
    end)
  end

  defp with_valid_headers(conn, action) do
    if get_req_header(conn, "banana") == "Cavendish" do
      action.()
    else
      send_resp(conn, 400, "Invalid banana")
    end
  end

  # ...
end

Of course, if this validation is not going to be reused, you can just place it in the body of the do block.

Paweł Obrok
  • 22,568
  • 8
  • 74
  • 70