Poison encoding different scopes of same schema

I’m wondering how everyone else solves this problem.

Say I have a very complicated schema in a big Phoenix application.

The schema describes a project which has tons of associations running up to 3 levels deep.

I return results to my frontend through channels, which are encoded by Phoenix through Poison.

My problem is that I need so many different versions of this data. Sometimes I just want the project, sometimes I want the project and the project members, sometimes I want everything etc. So that kind of ruins the @derive approach, since it changes so much.

The way I do it now is by niling out associations I don’t need on a case by case basis, but it just seems like it’s the wrong way to do it.

For instance:


    with {:ok, company} <- Companies.get_company(company_id),
         {:ok, _} <- Permissions.can?(user, :admin, company),
         {:ok, relationship} <- Relationships.get_relationship(partner_id, company_id),
         {:ok, relationship} <- Relationships.update_custom_price_list(relationship, price_list) do
           
      relationship =
        relationship
        |> Repo.preload([:partner, :provider])
        |> put_in([Access.key(:partner), Access.key(:price_list)], nil)
        |> put_in([Access.key(:provider), Access.key(:price_list)], nil)

      {:reply, {:ok, %{code: 200, price_list: price_list, relationship: relationship}}, socket}
    end

Any tips on how you folks manage stuff like this?

TIA!

I would probably try and write a query that wouldn’t fetch unnecessary data.

Have you tried rendering the response in a view?

defmodule Web.RelationshipView do
  use Web, :view

  def render("relationship_flat.json", %{
    relationship: %Relationship{some_key: some_value},
    price_list: price_list
  }) do
    %{
      "code" => 200,
      "price_list" => price_list,
      "relationship" => %{"some_key" => some_value}
    }
  end
end

And then in your channel module

# ...
reply = Web.RelationshipView.render(
  "relationship_flat.json",
  price_list: price_list, relationship: relationship
)
{:reply, {:ok, reply}, socket}
# ...
1 Like

Good question! It’s situations like this that led to the promotion of the “json view” pattern over using defimpl: http://www.rokkincat.com/blog/2015/03/17/json-views-in-phoenix

5 Likes

Thank you both! This makes much more sense to me!

New url for the article Ben posted:

https://rokkincat.com/blog/2015-03-17-json-views-in-phoenix/

1 Like