fireproofsocks

fireproofsocks

I’m wondering if anyone has any educational (i.e. simplified) examples that demonstrate best practices when it comes to handling bad requests in a Phoenix application. For educational purposes, let’s consider just one case:

Creating a record: how to handle a bad payload
Maybe your router has something like this:

  scope "/api", MyAppWeb do
    resources("/things", ThingController)
  end

And maybe your controller has something like this:

  def create(conn, %{"data" => data}) do
    with {:ok, thing} <- ThingCreate.create(data) do
      conn
      |> put_status(:created)
      |> render("thing.json", thing: thing)
    end
  end

You’ll notice that the route won’t pattern-match if your payload is something like [] (an empty JSON array)…

It’s tempting to write another controller function that would handle the bad data:

  def create(conn, _bad_data) do
    # return an error...

but that’s just smelly

This article looked promising, but it didn’t get into details: https://medium.com/appunite-edu-collection/handling-failures-in-elixir-and-phoenix-12b70c51314b

I think that the correct response for this situation would be a 400 (e.g. 422), but not simply a 404. What is the cleanest way to return an error message with specifics and a proper status code? Is this best handled in the fallback controller? Does anyone have a complete example of this?

Thanks for sharing!

Showing Posts 1 to 5

dimitarvp

dimitarvp

I don’t see that, you don’t have any additional assertions in the function’s head save for the map requirement with a singular "data" key – nor do you have when clauses. Why wouldn’t this:

def create(conn, %{"data" => data}) do

…match %{"data" => []}? Or you meant if the object itself is not a map at all and just []?

Assuming it’s the latter, then:

…is not a factual statement. In our team we use pattern-matching function heads all the time and they really do help readability and expressing your intent much better than huge case or cond arms in the code of a single controller action function.

fireproofsocks

fireproofsocks OP

I meant the latter: only an empty array being posted, not part of a data payload.

Of course, code smells are a matter of opinion.

So is your solution to add multiple controller functions to pattern-match on bad inputs? In this case you could get away with just one extra function… but then I start thinking about other edge-cases and I worry about having to keep adding other functions. Do you have an example you can share?

dimitarvp

dimitarvp

Example no, but I believe it’s quite okay for your web server to error out with HTTP 500 when the input is totally unexpected. Your web app is not Skynet.

Don’t overthink error handling. Pattern match on your expected data shape, return errors in a couple of valid cases where people might make small mistakes, and leave Phoenix/Cowboy to error out on everything else.

fireproofsocks

fireproofsocks OP

Hmm… I don’t think I agree with that. My understanding of HTTP response codes are that a 500 error response indicates that the problem is on the server and (importantly) that the client could retry the request. In the case of badly formatted data, that should be some type of 400, indicating that the request is bad and should not be repeated.

dimitarvp

dimitarvp

Sure, you caught me late at night not thinking entirely straight. Be proud! :stuck_out_tongue:

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews