jschaeff

jschaeff

Handling parsing body errors gracefully

I’ve implemented a module implementing the behaviour of Plug.Parsers

From the doc I followed, my parse/5 callback returns {:ok, params, conn} when the body has been successfully parsed.

But when there is a parsing error in the body, I think I have to return {:next, conn} so that Plug can go on to the next parsers.

When this happens, I have errors in my logs and the clients gets a 500 error, I would expect him to get a 415 or a 400.
Obviously I need to add something in my code to handle gracefully Plug.Parsers.UnsupportedMediaTypeError

Where should I put this ?

Here is an extract of my parse function:

require Logger
require Plug.Parsers.ParseError

defmodule Wsdataselect.BodyParser.ParseError do
  defexception message: "Malformed body"
end

defmodule Wsdataselect.BodyParser do
  @moduledoc """
  This modules parses the body of a HTTP request to generate a %Wsdataselect.DataRequest{} structure.
  """
  alias Wsdataselect.{DataRequest, Stream}
  @behaviour Plug.Parsers

  def init(opts), do: opts

  @doc """
  Parse the body of the request in order to return a %Wsdataselect.DataRequest{}
  This function implements the behaviour of Plug.Parsers.
  """
  @spec parse(Plug.Conn.t(), any, any, any, any) :: {:ok, DataRequest.t(), Plug.Conn.t()} | {:error, :too_large, Plug.Conn.t()} | {:next, Plug.Conn.t()}
  def parse(conn, _, _, _, _) do
    {:ok, body, conn} = Plug.Conn.read_body(conn)
    body_list = String.split(body, "\n", trim: true)
    if length(body_list) > Application.get_env(:wsdataselect, :post_max_lines) do
      {:error, :too_large, conn}
    else
      case Enum.reduce(body_list,  %DataRequest{}, &parse_line/2) do
        {:error, m} ->
          Logger.error(m)
          {:next, conn}
        datareq ->
          Logger.debug("Body parsed: #{inspect(datareq)}")
          {:ok, datareq, conn}
      end
    end
  end

And Here my router:

defmodule Wsdataselect.Router do
  @moduledoc """
  This module is the entrypoint of HTT requests from the user. It uses Plug to manage the requests.
  """
  require Logger
  require DateTime
  alias Wsdataselect.Controller
  use Plug.Router
  use Plug.ErrorHandler
  use Plug.Builder

  plug Plug.Logger
  plug Plug.Static,
    at: "/",
    from: {:wsdataselect, "priv/static"},
    content_types: %{"application.wadl" => "text/xml; charset=utf-8", "index.html" => "text/html"}
  plug Plug.RequestId
  plug :match
  plug Plug.Parsers, parsers: [Wsdataselect.BodyParser]
  plug :dispatch

  post "/query" do
    Logger.debug("Body: #{inspect(conn.body_params)}")
    conn
    |> Controller.post_query()
  end

When a body with wrong format is POSTed, the logs are:

16:07:57.070 request_id=F4B8-uvNBI9DfjkAAACE [error] GenServer #PID<0.637.0> terminating
** (Plug.Parsers.UnsupportedMediaTypeError) unsupported media type application/json

Where in my code should I put a Plug.Conn.send_resp(conn, 400, "Malformed body") ?

First Post!

jschaeff

jschaeff

I’ve added this to my router:

  @impl Plug.ErrorHandler
  def handle_errors(conn, %{kind: _k, reason: r, stack: _stack}) do
    send_resp(conn, conn.status, r.exception.message)
  end

And this line in my Parser:

raise %Plug.Parsers.ParseError{exception: %Wsdataselect.BodyParser.ParseError{message: m}}

Which makes a nice response to the client, but still crashes on the server side:

16:33:03.830 request_id=F4B-Wb0PupyhAfsAAAFj [error] GenServer #PID<0.626.0> terminating
** (Plug.Parsers.ParseError)

Where Next?

Popular in Questions Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
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
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
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
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

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
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
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
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement