Missed Opportunity: Phoenix needs a guide for creating REST APIs

The view still exists, it just renders the output in a different format (XML, json, text, …)

It’s as simple as

defmodule MyApp.Router do
  use MyApp, :router

  scope "/api", MyApp do
    pipe_through(:api)

    resources "/items", Api.ItemController
  end
end

defmodule MyApp.Api.ItemController do
  use MyApp, :controller

  def index(conn, params) do
    items = Context.list_items(params)
    render(conn, "index.json", items: items)
  end
end

defmodule MyApp.Api.ItemView do
  def render("index.json", assigns) do
    assigns.items
  end
end
1 Like

Going to chime in to say that the lack of direct API demos was a major irk for me when beginning with Phoenix. Also, there’s a strong bias towards tutorials assuming familiarity with Ruby on Rails – which, coming from other tech, was not a straight forward or happy feeling.

I’ve really enjoyed Elixir for everything except the web stuff.

11 Likes

I’ve never really understood the utility of dispatching on a string (“index.json”) in the views when building REST APIs. What’s the advantage over directly calling a function like this?

defmodule MyApp.Api.ItemController do
  use MyApp, :controller
  alias MyApp.Api.ItemView

  def search(conn, params) do
    items = Context.list_items(params)
    ItemView.render_many(items)
  end
end

defmodule MyApp.Api.ItemView do
  def render_many(items) do
    items # or whatever logic
  end
end
4 Likes

There are a few things Phoenix.Controller.render does for you:

  • It merges your data with the current assigns and converts the result to a map
    (views don’t support keyword lists)
  • It does automatically set the content type for you
  • It does dispatching to layout views if you use them
  • It calls the view functions, which return iodata, so it can benefit from the performance gain of not building large binaries
  • It sends the templated data as response

So it’s basically a shortcut to remove a bunch of boilerplate you’d have to write on your own otherwise.

4 Likes

I’m referring to the directory of the templates, the real V of MVC which the user will interact. Phoenix.View is coupled to the framework and you’ll need to use it whenever you create a MVC app or an API, as it’s required in order to render / expose data just like you’ve said.

In other frameworks the type of data returned is specified inside the controller (sometimes globally inside the core of the app) or detected by the framework itself. So, I believe that Phoenix.View acts like an extension of the controller either by interacting with the template or just by specifying the data to return, and that’s a bit confusing (correct me if I’m wrong, but that’s what I guess from my experience). If I’m right I’ll love to know why Phoenix exposes this “views” directory instead of doing everything from the controller.

Most of the time in a normal MVC app the “WhateverView” module is almost empty, I just use it for defining a title.

That’s is because of EEx, which actually compiles templates into functions of the view module. The compiled project only has modules and no template files anymore. This makes it quite a bit faster than frameworks without precompiled templates. That’s also why json and html views actually work with the same api even if one is using written out render functions and the other is using templates. Both are called using render/2 on the view module.

You could even use the render function to e.g. prepare date for the template:

def render("show.html", %{date: date} = assigns) do
  data = %{assigns | date: Date.to_iso8601(date)}
  render_template("show.html", data)
end

So the view is hardly as useless as the mostly empty modules make it look like. It’s more due to the fact that phoenix is compiling the 95% use-cases so efficiently into the module that often times you don’t need to modify it. But if you do to you can.

You can do the same in plug/phoenix as well: json(conn, data). But it means your data must be json-encodable by globally defined rules. This get’s problematic as soon as you want to have more than one json representation based on the same data. If you want to work around that limitation just in the controller you’d put a lot of data mapping logic into the controller, while phoenix simply encourages to put all that logic into a view module right from the start (which is also where it really belong).

3 Likes

We do have a section about rendering JSON for apis in the guides:

https://hexdocs.pm/phoenix/views.html#rendering-json

If someone would like to expand on this and/or make it more discoverable, we would love a guide contribution. Thanks!

16 Likes

I marked Chris’s post as the solution for this thread :003:

2 Likes

This is certainly a very nice feature of EEx but it is not the reason to separate Views from Templates/Controller.

@adrianrl
I believe the reason is to separate template helpers (something like format_date that would be defined in the View module) from other functionality that lives in the controller.

In my experience I have found that I want to reuse most view helpers across more than one template and so my View modules are normally pretty empty, me helpers end up in some other utils module.

Just to demonstrate that compile time templates do not require a view, here is an example what I am doing with a Raxx project I have

defmodule MyApp.ShowUser do
  use Raxx.SimpleServer

  use Raxx.View,
    arguments: [:user],
    template: Path.join(__DIR__, "show_user.html.eex"),
    layout: Path.join(__DIR__, "_layout.html.eex")

  def handle_request(_request, _config) do
    user = get_a_user()

    response(:ok)
    |> render(user)
  end
end

The template is read and compiled once, and everything lives in MyApp.ShowUser.

3 Likes

Respectfully, I don’t think that Chris’ post is a solution to the thread. Imagine yourself in the position of being completely new to Phoenix and possibly Elixir. Perhaps you have no experience with rails either. Their goal is to learn Phoenix with the express purpose of evaluating it for REST API development. If you proceed through the Phoenix docs or through the “Programming Phoenix” book, there are brief mentions of API creation, but those mentions are obviously far overshadowed by the main theme of the documentation - building self contained web apps with server rendered html.

I’ve heard it dismissively said that Phoenix produced JSON APIs are trivial and are merely JSON views or something to that effect. And perhaps the development of JSON APIs are very easy compared to developing a self contained web apps. All the better. But people that say this already have a very complete understanding of Phoenix. It’s entirely possible that someone new to Phoenix has no real concept of Phoenix endpoints, controllers, views, routers, templates, etc. To tell them that Phoenix API development consists merely of JSON views is meaningless.

My point is simply this. I think if there were an officially supported Phoenix guide for developing REST/JSON APIs, Phoenix’s user base would be increased and this would be a good thing for Phoenix and Elixir.

18 Likes

I’ve heard it dismissively said that Phoenix produced JSON APIs are trivial and are merely JSON views or something to that effect.

I think that’s because mix.gen.json makes it so easy to scaffold a basic REST API, and if you got how to use phoenix html, it boils down to understanding how to write tests in elixir, ecto and maybe a few other components more than anything. That might lead people to “dismissively say” that :slight_smile:

My point is simply this. I think if there were an officially supported Phoenix guide for developing REST/JSON APIs

I am not really opposed to that, but I feel like it would be almost exactly the same as the “regular” guide - which already includes a part talking about rendering JSON.

What about this bit:

Perhaps you can help create such a guide if you feel the current one is lacking? You could post in the #your-libraries-projects:projects section to seek others who might be able to help? Perhaps @doomspork and the ElixirSchool folks might be able to offer their assistance or maybe create a section for such tutorials as well?

The great thing about the Elixir community is that it’s quite possible you’ll be able to find someone who shares the same idea, and may be willing to help. And if you can’t… our community is very receptive to ideas on on-boarding and adoption, so you’re only as limited as your skills of persuasion :003:

5 Likes

I think people that think REST API responses are fundamentally different from html responses don’t really understand the ‘R’ in REST ¯\(ツ)

But, yeah, I’m open to a PR improving the docs. :+1:

2 Likes

Thanks for thinking of us @AstonJ :purple_heart: We’ve been discussing Phoenix lessons and would welcome input from others.

@chuck what things specifically would you like to see covered? I’d be happy to set aside some time for a blog series to help yourself and others until we can formulate a plan for actual lessons (and translations).

If you’re interested in collaborating together let me know! Always happy to help folks :grin:

8 Likes

Ideally, there would be complete end-to-end documentation for Phoenix for API developers. It wouldn’t assume any knowledge of Phoenix. It would be updated to reflect any changes introduced by new releases of Phoenix, i.e. it should be supported.

A lower effort alternative would be parallel sections in the current documentation with information specific to API developers.

An even lower effort alternative would be a separate guide devoted to API development.

I would and may help with these eventually, but right now I’m not far enough along on the learning curve myself.

2 Likes

I’m still wondering what would people like to have in there content wise?

2 Likes

I think they will need more specifics. Since I’m on the same boat as you - Learning Elixir and Phoenix while developing Web APIs - I’ll try to help:

It’d be great if the Phoenix guide have a section on Web APIs. This will save us time as we don’t have to find the info inside the Views section.

That section should start by stating that a great way to start is by running the generator with the no-html and no-webpack options.

It should also mention that if you’re not using a database and you don’t need bi-directional communication, you might consider not even using Phoenix at all as Elixir, Plug, Cowboy and Jason should be sufficient.

Then, it could mention that other stuff you need is the same as regular Elixir development, e.g. Supervisors, GenServers, ETS, CacheX, CVS and/or XML parsing, etc.

That’s a very short summary of what I have learned. What do you think? Am I forgetting anything important?

4 Likes

What does this mean to you though? What are the specific topics you’re not clear on? “Complete documentation” means something different to everyone who reads it.

Are you looking documentation down to what JSON and an API are? I’m trying to get a sense of how granular you’re looking to go.

If you were going to write a book for developing JSON APIs, what chapters would it have to have?

1 Like

We’re working on a blog series over at elixirschool.com on this very thing! The first post does focus on HTML just to illustrate how simple that can be without Phoenix but there is a small section on using JSON: Building web apps with Plug.Router | Blog · Elixir School. Next post will cover deploying our sample application to Heroku followed by a post series focused on building JSON only API using Plug.Router. I’m sure we can find a way to work in a post on using Phoenix for the same task.

I’m not sure this fits in a guide to developing JSON APIs though. We have most of this content on elixirschool.com already. Maybe we would benefit from a section focused on apply of these concepts?

We started on a repo of partial projects that you can finish yourself to explore Elixir but it could certainly be improved: GitHub - elixirschool/homework: A collection of coding exercises to be completed in conjunction with the lessons available on elixirschool.com

1 Like

I was just suggesting that the Web API section should state something like “from here on is the same as any other Elixir app”, or “For all these subjects, see their specific sections”. It’s just to emphasize what everyone keeps telling you the first time you ask the question which is: “there’s no really much difference” :slight_smile:

Perhaps, the question won’t be asked this often then.

Great news about the new upcoming content. Keep up the good work

4 Likes