arcanemachine

arcanemachine

Looking for an easy way to raise HTTP errors (e.g. 422) with messages in a RESTful JSON API

TL;DR

I want to be able to do something like raise Plug.HTTPError, plug_status: 501, message: "Some optional message" so that I can easily return helpful errors in a RESTful JSON API that I am working on.

The status code may change, and the message is optional.

I don’t want to have to have to create an exception for this because it comes up in every API I work on, so it makes sense (to me) to have a one-liner solution ready to go.

The Issue, and Why I Am Searching for a Solution

I am working on a RESTful JSON API using Phoenix, and am frequently dealing with the issue of having to abort a request for various reasons, e.g. 422 errors for client-side issues (like some input that is determined to be invalid at some point during the request), 501 errors for server-side issues (like we haven’t implemented an action for a request that contains a certain parameter), and so on.

This can happen at various stages of the request, for a variety of reasons. The conn may or may not be available as part of the function call. But at some point it happens that:

  • The request needs to be aborted with a certain HTTP status code,
  • With a helpful error message, and
  • This should be accomplished in a clean manner with minimal hoop-jumping.

How I’m currently solving the problem.

What I am currently doing is e.g. raise Plug.BadRequestError, plug_status: 501. I’m using Plug.BadRequestError since it is one of the few ready-to-use implementations of a plug exception defined in the Plug library itself.

It works great. Now, in my ErrorJSON module, I just have to add this:

  def render(<<_status::binary-3>> <> ".json", %{reason: %{message: message}} = _assigns) do
    %{errors: %{detail: message}}
  end

And now, I can, in 1 line, from anywhere in the Phoenix application, raise an exception with any desired status code, and terminate the request quickly, easily, and cleanly, while showing a helpful message to the consumer of the API.

The Problem With My Solution

Obviously, the Plug.BadRequestError is intended for a specific use case. Is there a better way to raise a generic exception? (I would strongly prefer not to have to litter each app with a new module for such a common (for me) task.)

Tell Me What You Think

Please let me know your thoughts on the situation.

I have thought that it may be nice to have a generic exception ready to use in the Plug library for this (e.g. Plug.HTTPError, or Plug.Error or Plug.CustomError).

If you have a better solution to this problem, I would be glad to hear it. :slight_smile:

Most Liked

D4no0

D4no0

I would personally use the fallback controller for this:

defmodule MyFallbackController do
  use Phoenix.Controller

  def call(conn, {:error, :unauthorized, message}) do
    # Choose here how to render your custom message
    conn
    |> put_status(:forbidden)
    |> put_view(MyErrorView)
    |> render(:"403")
  end
end

Then you can use the shape of {:error, :unauthorized, message} (or whichever else you like more) to always fallback to this controller that knows how to render the specific error.

Personally, I always end up using the action_fallback instead of throwing error as it is more of a “functional” approach.

sodapopcan

sodapopcan

Ah ya, I guess I’m off topic as I’m not talking APIs (I have yet to have to make one in Phoenix… well, I did sort of work on one at my old job but barely touched it… anyway). But ya, generally if everything is controllers halting is better.

Where Next?

Popular in Questions Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
New
Kurisu
For example for a current url like http://localhost:4000/cosmetic/products?_utf8=✓&amp;query=perfume&amp;page=2, I would like to get: ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New

Other popular topics Top

New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43757 214
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39467 209
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement