Przemek
How to catch Plug.Parsers.ParseError
I’ve spent a while, read some posts to no effect
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
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
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 ![]()
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









