adriancarayol

adriancarayol

Hello everyone,

I am building a new application with Phoenix to intercept requests (any kind of request). The idea is, basically, to store all requests in a DynamoDB table, as if it were a request log: HTTP method, query params, headers, …

I am having some problems when taking the raw body request. I have seen some posts suggesting to use :body_reader, like:

plug Plug.Parsers,
  parsers: [:urlencoded, :json],
  pass: ["*/*"],
  body_reader: {CacheBodyReader, :read_body, []},
  json_decoder: Jason

but I can’t get it to work, sometimes the parameters arrive in conn.body_params.

To give an example, in Go, it is really easy to obtain the body in raw form, with:

// full dump of the request
dump, err := httputil.DumpRequest(c.Request(), true)
// body
b, err := io.ReadAll(c.Request().Body)

I think I’m a little bit obfuscated and I can’t see the light :grin:

Thank you for your help.

Showing Posts 1 to 6

pdgonzalez872

pdgonzalez872

Hi @adriancarayol, welcome!

Did you create the CacheBodyReader like the docs mention? Plug.Parsers — Plug v1.20.2

You need to create that file as well as adding that snipped you posted. Please try that and let us know what issues you find then? Thanks!

adriancarayol

adriancarayol OP

Hi @pdgonzalez872 , thanks!

Yes, I have created the CacheBodyReader like the docs.

The problem is that it seems that if the content-type is not registered in the parsers, it does not work, for example:

curl -X POST http://localhost:4000 \
  -H “Content-Type: application/x-yaml” \
  -d “---
name: John Doe
age: 30
city: New York”

The assigns field in the conn struct it’s empty.

conn #=> %Plug.Conn{
  adapter: {Bandit.Adapter, :...},
  assigns: %{},
...
}

The controller it’s pretty simple:

defmodule InterceptorWeb.RequestController do
  use InterceptorWeb, :controller

  def receive(conn, _params) do
    dbg(conn)

    json(conn, %{message: "Hello, Interceptor!"})
  end
end

The idea is to be able to capture any type of request, regardless of its Content-Type.

jswanner

jswanner

It’s currently configured to only allow MIME types starting with “text/“:

Change that to: pass: ["*/*"]

adriancarayol

adriancarayol OP

Sorry @jswanner , it’s wrong in the OP, the configuration is as you say, but still, it does not work correctly.

pdgonzalez872

pdgonzalez872

I see. I tried it out and agree, it doesn’t seem to get parsed/ingested at all.

After a bit of digging, it turns out that it is the Content-Type in that curl request that is the problem, not the body. FYI - If you switch it to json and pass in valid json, it works out of the box.

To make your current setup (that curl script) “work” is very interesting and I hope you can see how the team building and working on these tools are excellent. I say that because they offer great defaults but also allow you to do whatever you want, like we see this person doing with xml (https://stackoverflow.com/a/36202176). To make it work, you’d need to implement a parser that takes in x-yaml and parses it correctly. You will see sane defaults, great docs and also these “scape hatches” throughout the libraries in the community.

To solve for your OP question (and maybe a follow up you may have), accepting ALL kinds of requests requires a parser that takes anything you give. Be careful, this sounds dangerous →

Disclaimer: The Phoenix team knows way more than I do so I’m sure there are GOOD reasons to not accept every kind of request and that these defaults are great ones to have. Since you are returning json, could you also make the curl/what sends you the posts send json as well? I’ve never worked anything other than the defaults and looked into this because I was curious about how it all worked. But hey, maybe you do have a valid use case. I’ll let folks that know more chime in about it.

In the discussion above, [*/*] Seems to have nudged you that it would accept everything and I think it’s the crux of the confusion. It DOES accept and respond to your request :slight_smile:, what it doesn’t do is parse the body because the content-type was not defined (no x-yaml). That’s why you don’t see it in assigns. To see it, seems like we need to write a parser, like the person that wanted to do the xml one likely did. I won’t parse the yaml for you, that’s an exercise for the reader. So, let’s look at the parsers that come out of the box, here is the urlencoded one: plug/lib/plug/parsers/urlencoded.ex at v1.16.1 · elixir-plug/plug · GitHub

So, here is a naive implementation that shoves things into assigns:

defmodule CatchAllParserDanger do
  @behaviour Plug.Parsers

  @impl true
  def init(opts) do
    opts
  end

  @impl true
  @doc """
  https://hexdocs.pm/plug/Plug.Parsers.html#c:parse/5
  """
  def parse(conn, "application" = _type, _subtype, _params, opts) do
    {:ok, body, conn} = Plug.Conn.read_body(conn, opts)
    conn = Plug.Conn.assign(conn, :raw_body, body)
    {:ok, %{}, conn}
  end

  @impl true
  def parse(conn, _, _, _, _) do
    {:next, conn}
  end
end

Then we need to adjust our app, here are some diffs:

# endpoint.ex
-    parsers: [:urlencoded, :multipart, :json],
+    parsers: [:urlencoded, :multipart, :json, CatchAllParserDanger],

# router.ex
   # Other scopes may use custom stacks.
-  # scope "/api", EFWeb do
-  #   pipe_through :api
-  # end
+  scope "/api", EFWeb do
+    pipe_through :api
+
+    post "/adriancarayol", PageController, :receive
+  end

# page_controller.ex
+  def receive(conn, _params) do
+    IO.inspect(conn.assigns)
+
+    json(conn, %{message: "Welcome!", raw_body: conn.assigns.raw_body})
+  end

Using your curl, in a script:

#!/bin/bash

curl -X POST http://localhost:4000/api/adriancarayol \
  -H "Content-Type: application/x-yaml" \
  -d "---name: John Doe age: 30 city: New York"

Running the server and calling the script gives this in our logs:

[info] POST /api/adriancarayol
[debug] Processing with EFWeb.PageController.receive/2
  Parameters: %{}
  Pipelines: [:api]
%{raw_body: "---name: John Doe age: 30 city: New York"}
[info] Sent 200 in 21ms

and returns:

ef [main] $ ./curl_test.sh
{"message":"Welcome!","raw_body":"---name: John Doe age: 30 city: New York"}ef [main] $

Also, the person wanting to accept xml linked this: Way to Read Request Body As String · Issue #459 · phoenixframework/phoenix · GitHub in their accepted answer, pretty neat and pretty much what I showed above.

Hope this helps! But again, please read the disclaimer above :heart: and welcome to the community!

adriancarayol

adriancarayol OP

Thank you very much for your reply @pdgonzalez872 ! Definitely this use case is not something usual, in the years I’ve been using Phoenix I’ve never had to use something like this (and of course you have to use it carefully :icon_smile:!).

Again, thanks and long life to Phoenix :vulcan_salute: !

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews