243 words, 2 min read

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.