JSON Views in Phoenix

Lately there has been discussion around rendering Ecto models for a JSON style API in Phoenix. I am part of the core Phoenix team, and I typically use Phoenix to build API’s. I am here to show you an example of using views to render JSON.

Right now there is a very common meme to use PoisonProtocols to render your JSON object.

All of your helper functions defined in the view are automatically available.

If you had to modify your output, it would be obvious what to do next. Go check the view.

So this is a pretty simple example, but even in it there lie some bugs.

The first and less interesting bug, is what happens if my associations are not pre-loaded?

In both examples Ecto will raise an exception.

How are the associated model’s user and comments rendered?

In the Poison example, it would attempt to apply the encoder protocol on the associations struct, and if it couldn’t, it would fall back to the basic struct. In our example, the same thing would happen! We haven’t explicitly defined the user or comment implementation.

Here is how I would update our example to properly render the associations:

You’ll notice my view code has grown quite a bit. I added an encode function for simplicity of calling it from other views. I might even redefine the encode functions to look like this.
Because I find it more obvious what is going on and can see at a glance what the JSON body might look like.

I want to point your attention to my encode_lite/1 function in the UserView. My CommentView only requires the basic info about a user. To accomplish this I defined a new function body and called it.

In the case of the Poison.Encoder I would need to explicitly call Poison.encode!(comment.user, lite: true) and have a conditional in my user implementation to handle the option of lite.

As the API project grows and your services become more complex, cases like these become the rule instead of the exception. Views give you the flexibility required to do basically anything you want, it’s just function calls and maps.

Next time I’ll show a more complex example that uses the JSON API spec and I’ll show off some helpers I’ve built to reduce some of the obvious duplication in my views.