How to handle actions with not matching parameters

I’ve created a JSON API and deconstruct parameters in the controller action like this:

def create(conn, %{“item” => item_params}) do

end

Now I’d like to capture the cases where the pattern isn’t matched (e.g. not having the “item” in the request JSON) and send an appropriate error JSON.

How can this be done? Now I just get “no function clause matching in …create/2” error. After some research I found the following issue which would suit my needs, but it was closed by José:

Write a second clause for the function:

def create(conn, params)

def create(conn, %{“item” => item_params}) do
  do_stuff()
end

def create(conn, _params) do
  send_error()
end
1 Like

I actually thought about this, but then I asked me, how can Elixir know which function to take for a valid request? In that case both functions would match, right? How is the priority handled in Elixir? Sorry, this is a very basic question as I’m new to Elixir/Phoenix…

The pattern matching is applied top to bottom:

# This is optional.
def create(conn, params)

# Attempted first, matches on correct params.
def create(conn, %{“item” => item_params}) do
  do_stuff()
end

# Matches everything else.
def create(conn, _params) do
  send_error()
end
3 Likes

Ah, thanks for this, that’s essential to know!

I just wanted to point to the documentation about pattern matching in functions, but there seems to be none. Neither in elixir-hexdocs nor in the guide…? Am I missing something?

2 Likes

How about Pattern matching - The Elixir programming language

EDIT: oh, I see. There’s no mention of pattern matching in function heads.

3 Likes

There is sth here Functions · Elixir School
But its not part of the official docs.

2 Likes

I am also confused by this.

José Valim here:

The ActionClauseError is already rendered as the appropriate 400, so you likely don’t need to do anything here.

Chris McCord here:

This is as designed since we don’t wrap and translate errors when debug_errors is enabled. It is false by default, so test and prod will return. your 400 as you want. Thanks!

The phoenix docs:

to provide custom error pages, we could simply define a proper render/2 function clause in HelloWeb.ErrorView.

However, in all the examples provided above and in the linked GitHub issues, and in my test, the error is not handled by Phoenix, the Plug.Exception protocol is unused, and the program crashes with the uncaught exception (a generic 500 error is thrown if accessing via the browser, exception is uncaught in tests).

Is something supposed to catch these Plug.Exception exceptions and route them to the ErrorView, or is this only for debugging?

It works fine for me here:

One thing to note is that the Phoenix.ConnTest API is not meant to catch exceptions as they skip the outer http parts of handling a request. You also generally want the exceptions details in tests to be able to debug issues. Other frameworks usually need code to disable that.

You can test Plug.Exception working though by enabling the server in the test env and doing full http requests.

2 Likes

Thank you! ConnTest behaving differently to HTTP requests was tripping me up, thanks for pointing that out - and for the demo. Super helpful.