When building APIs or proxy-style endpoints in Phoenix, you might occasionally need a single route to handle multiple HTTP methods - like GET, POST, PUT, DELETE, and even OPTIONS.

While Phoenix typically uses one macro per method (e.g., get, post), there's a lesser-known match/5 macro that gives you more flexibility.

Phoenix’s match/5 macro allows you to define a route that responds to multiple HTTP verbs:

# router.ex
match :*, "/api/endpoint", MyAppWeb.APIController, :handle

This line tells Phoenix to route any of the listed HTTP methods on /api/endpoint to APIController.handle/2.

A common scenario is handling CORS preflight requests (OPTIONS) in combination with other CRUD operations on the same path:

defmodule MyAppWeb.APIController do
  use MyAppWeb, :controller

  def handle(conn, _params) do
    case conn.method do
      "OPTIONS" ->
        conn
        |> put_resp_header("access-control-allow-origin", "*")
        |> put_resp_header("access-control-allow-methods", "GET,POST,PUT,DELETE,OPTIONS")
        |> send_resp(204, "")

      "GET" ->
        json(conn, %{message: "This is a GET request"})

      "POST" ->
        json(conn, %{message: "Data created"})

      "PUT" ->
        json(conn, %{message: "Data updated"})

      "DELETE" ->
        json(conn, %{message: "Data deleted"})

      _ ->
        send_resp(conn, 405, "Method Not Allowed")
    end
  end
end

Pros

  • One controller action for all methods
  • Useful for generic APIs, CORS handling, and proxies

Cons

  • Less idiomatic than Phoenix’s standard RESTful routes
  • Controller action becomes more complex
  • No compile-time route method checks

The match/5 macro is a powerful tool when you need flexibility in routing HTTP methods. Use it carefully—it's not a replacement for conventional RESTful design, but it's perfect for those cases where the router needs to get out of your way.