Running a plug pipeline after request is processed

430 Views Asked by At

Plugs pipelines are an amazing way to build applications. Currently though I've only been applying pipelines to filter/format data before the request hits the controller. Is there a way to apply a pipeline to run after every view is processed? I have a JSON api that I run two data transformations on every single view render function.

  def render("app.json", %{app: app}) do
    app
    ...
    |> ApiHelpers.add_data_property
    |> ProperCase.to_camel_case
  end 

Is there a cleaner way of handling this or is this something I just need to do on every render function in my view modules?

UPDATE

As @sabiwara pointed out there's the register_before_send callback. I've tried implementing it for my use case but it seems the callback is more for logging than manipulating the response.

I've tried

  def call(conn, _opts) do
    register_before_send(conn, fn conn ->
      resp(conn, conn.status, conn.resp_body |> FormatHelpers.camelize() |> ApiHelpers.add_data_property())
    end)
  end

conn.resp_body is a list I've tried transforming it to a map but still no good.

1

There are 1 best solutions below

0
On

One way to tranform the JSON content before it gets encoded is to define a custom encoder in the config: https://hexdocs.pm/phoenix/Phoenix.Template.html#module-format-encoders

Add in a new file:

defmodule MyJSONEncoder do
  def encode_to_iodata!(data) do
    data
    |> transform_data()
    |> Jason.encode_to_iodata!()
  end
  
  def transform_data(data) do
    # whatever transformation you need to make
    %{data: data}
  end
end

And to config.exs:

config :phoenix, :format_encoders, json: MyJSONEncoder

Not 100% sure it is the best way, and it will touch every single response, but it seems to be working fine for your use case.