tanweerdev

tanweerdev

Write Malformed JSON in the body Plug

I am trying to write a plug which will generate a custom error if the request has malformed JSON which is quite often the case in our scenarios(as we use variables in postman. eg sometimes there is no quote outside the value and it results in malformed JSON). The only help I got is https://groups.google.com/forum/#!topic/phoenix-talk/8F6upFh_lhc which isnt working of course.

defmodule PogioApi.Plug.PrepareParse do
  import Plug.Conn
  @env Application.get_env(:application_api, :env)

  def init(opts) do
    opts
  end

  def call(conn, opts) do
    %{method: method} = conn
    # TODO: check for PUT aswell
    if method in ["POST"] and not(@env in [:test]) do
      {:ok, body, _conn} = Plug.Conn.read_body(conn)
      case Jason.decode(body) do
        {:ok, _result} -> conn
        {:error, _reason} ->
          error = %{message: "Malformed JSON in the body"}
          conn
          |> put_resp_header("content-type", "application/json; charset=utf-8")
          |> send_resp(400, Jason.encode!(error))
          |> halt
      end
    else
      conn
    end
  end
end

Marked As Solved

tanweerdev

tanweerdev

in endpoint.ex file add a custom body reader and your custom plug in below order

plug Api.Plug.PrepareParse # should be called before Plug.Parsers

plug Plug.Parsers,
  parsers: [:urlencoded, :multipart, :json],
  pass: ["*/*"],
  body_reader: {CacheBodyReader, :read_body, []}, # CacheBodyReader option is also needed
  json_decoder: Phoenix.json_library()

Define a custom body reader

defmodule CacheBodyReader do
  def read_body(conn, _opts) do
    # Actual implementation
    # {:ok, body, conn} = Plug.Conn.read_body(conn, opts)
    # conn = update_in(conn.assigns[:raw_body], &[body | (&1 || [])])
    # {:ok, body, conn}
    {:ok, conn.assigns.raw_body, conn}
  end
end

Then your custom parse prepare

defmodule Api.Plug.PrepareParse do
  import Plug.Conn
  @env Application.get_env(:application_api, :env)
  @methods ~w(POST PUT PATCH)

  def init(opts) do
    opts
  end

  def call(conn, opts) do
    %{method: method} = conn

    if method in @methods and not (@env in [:test]) do
      case Plug.Conn.read_body(conn, opts) do
        {:error, :timeout} ->
          raise Plug.TimeoutError

        {:error, _} ->
          raise Plug.BadRequestError

        {:more, _, conn} ->
          # raise Plug.PayloadTooLargeError, conn: conn, router: __MODULE__
          error = %{message: "Payload too large error"}
          render_error(conn, error)

        {:ok, "" = body, conn} ->
          update_in(conn.assigns[:raw_body], &[body | &1 || []])

        {:ok, body, conn} ->
          case Jason.decode(body) do
            {:ok, _result} ->
              update_in(conn.assigns[:raw_body], &[body | &1 || []])

            {:error, _reason} ->
              error = %{message: "Malformed JSON in the body"}
              render_error(conn, error)
          end
      end
    else
      conn
    end
  end

  def render_error(conn, error) do
    conn
    |> put_resp_header("content-type", "application/json; charset=utf-8")
    |> send_resp(400, Jason.encode!(error))
    |> halt
  end
end

Also Liked

NobbZ

NobbZ

That will read the body, if it hasn’t been read before, eg by Plug.Parsers.

After you have read the body, you should put the parsed data somewhere in the conn, or it will be lost.

Where Next?

Popular in Questions Top

SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
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
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
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
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
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
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
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 Postg...
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

Other popular topics Top

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
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
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
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
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
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
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement