How do you cleanly compose within Phoenix JSON views?

Does anyone have strategies for cleaning up Phoenix views? I’ve been looking for blog posts or other online resources but none of them go in detail about how to structure views for long-term maintainability as they begin to take on multiple responsibilities.

Currently my views are getting cluttered because we’re passing in a scope_id which is usually a user id but sometimes it is something like a room_member_id (which denotes that a user has access to a given room). This can be useful to basically check authorization but it also makes it a bit messy.

Also we currently have two sets of views to represent one resource, one for REST and another for channels. Does anyone have suggestions or “best practice” suggestions?

Overall, break up your views into lots and lots of little reusable parts.

Yeah that definitely makes sense overall. I’m just having some trouble with the particulars. Took a little bit to find a good example.

Imagine a basic chat application that has multiple persistent rooms for conversation. It has a REST interface and a Channel based interface with the following properties/features:

  • When a user joins they request the list of rooms over the Phoenix Channel, each list includes a count of how many unread messages the user has in that room. This also includes additional information that only authorized users should see
  • When the user requests the room via REST it does not include the additional fields only for authorized users (to ease caching and because that’s the typical user of the GET REST endpoint)
  • When a user updates a room over the REST interface no unread message count is included
  • When another user updates a room a broadcast message is sent over the channel

The last scenario is trickiest because typically when viewed from a channel a room includes the unread messages count. But to add the unread messages to that broadcast is expensive, both computationally and in engineering effort (we’d need to intercept the broadcast and insert the unread messages per-user).

With such a setup how many different Views would you recommend and what would the public interface be to them. I’m currently playing with two, one View for the channel-based interface and another for the REST based interface with the REST based one usually calling methods from the channel-based view. But composing only from render/2 is proving difficult since it’s hard to know what fields to include in a response. Does anyone have examples of a more complex JSON view-based rendering setup?

If I were making an advertisement for GraphQL, this would be one of the front and center user stories :wink:

1 Like

Yeah definitely, just not quite ready to make the plunge yet. But maybe I’ll bring it up internally.

Yeah understood. FWIW We’ve actually seen folks do sort of a hybrid where you build a GraphQL schema in your application, and then in your controllers or your channel you can have a GraphQL query on the server that you run to select whatever values you want specifically for that situation.

This way your clients get totally ordinary REST responses or websocket responses, but you don’t have to code for all the different scenarios, and you get a GraphQL API along the way.

1 Like

Yeah this is actually pretty awesome to do.