Przemek

Przemek

How to catch Plug.Parsers.ParseError

I’ve spent a while, read some posts to no effect :confused: How can I add a handler so that when malformed JSON is posted, I am not getting a standard HTML page, but my own JSON response (from ErrorView)?

Log fragment:


[debug] ** (Plug.Parsers.ParseError) malformed request, a Poison.SyntaxError exception was raised with message "Unexpected token at position 2: e"
    (plug) lib/plug/parsers/json.ex:54: Plug.Parsers.JSON.decode/2
    (plug) lib/plug/parsers.ex:221: Plug.Parsers.reduce/4

Most Liked

m1dnight

m1dnight

I know this thread is pretty old, but it’s high up in the search function. I managed to find a semi-elegant solution for this.

I made a custom plug to call out to Plug.Parsers and handle any exceptions it throws.

defmodule DataApiWeb.Plugs.QuietJSON do
  @behaviour Plug
  import Plug.Conn

  @impl true
  def init(opts) do
    # Create the optoins that `Plug.Parsers` expects.
    Plug.Parsers.init(opts)
  end

  @impl true
  def call(conn, opts) do
    Plug.Parsers.call(conn, opts)
  rescue
    Plug.Parsers.ParseError ->
      conn
      |> put_resp_content_type("application/json")
      |> send_resp(400, ~s({"error":{"detail":"Malformed JSON"}}))
      |> halt()
  end
end

Then, in my endpoint.ex I’ve made this change:

  # plug Plug.Parsers,
  plug DataApiWeb.Plugs.QuietJSON,
    parsers: [:urlencoded, :multipart, :json],
    pass: ["*/*"],
    json_decoder: Phoenix.json_library()

This approach simply takes in the options from the original plug and passes them on to the wrapped plug.

On malformed data, the plug returns the error message {"error": {"detail": "Malformed JSON"}} and you shouldnt see any error logs anymore.

A sample test I added to verify the behavior:

    test "invalid JSON body returns a clean 400", %{conn: conn} do
      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> post(~p"/api/health", "{not-json")

      assert %{"error" => _} = json_response(conn, 400)
    end

The reason I needed this was because some bots were spamming and it polluted my log files.

Przemek

Przemek

Sort of… In endpoint.ex I replaced Poison with my own JSON decoder (btw Jason is faster) that wraps decode with try/catch. On parsing error it sets an error that I handle in controller… It works, but of course sucks. I am also interested in a better way :slight_smile:

Nicd

Nicd

Did you manage to solve this @Przemek? I would also be interested in the answer.

Where Next?

Popular in Questions Top

Kurisu
For example for a current url like http://localhost:4000/cosmetic/products?_utf8=✓&query=perfume&page=2, I would like to get: ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: <h1>Create Post</h1> <%= ...
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
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
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
New

Other popular topics Top

siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
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 43806 214
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement