API Design – Specialized Endpoints vs Multiple Calls to Generic Resources

apiapi-designdesignrest

This problem came up while designing the API for a SPA web application, which communicates with the server via AJAX.

On one page the user, who is creating a list of people to invite to an event, has the option to add people who were invited to previous events. Imagine a dropdown containing the names of the previous events. When an event is selected, a multiselect is filled in with everyone invited to that previous event. The user can select from these people, and press "Add," which adds them to the invite list for the current event.

If you imagine the data structure behind the dropdown / multiselect described, it might look something like this:

previousEventGuests [
  { 
    eventName: 'Company Christmas Dinner',
    guests: ['Joe Smith', 'Andy Jones', ...]
  },  
  ...
]

The question arises: How is this information downloaded from the API?

I see two high-level approaches:

  1. Write an specific API endpoint to address this specific need:

    /previousEventsAttendees
    

which returns exactly the data above.

  1. Make multiple calls to generic resource endpoints

    /events                    (foreach event_id returned, call....)
      /event/:event_id         (to get each event's name)
      /event/:event_id/guests  (forach list of user_ids returned, call...)
        /user/:id              (to actually get each users name)
    

The pros of 1. are that you only have to make a single AJAX call, and you have far less data processing code on the client. The major con I see is that you've built an endpoint tightly coupled to this particular view within this particular application.

The pros of 2. are that we are using nothing but generic resource endpoints, which could be re-used by many different views and applications. The cons are that we have to make many AJAX calls, and piece together all the responses to get the format we want.

My questions are:
1. What factors should I be considering when making these kinds of decisions? Should the fact that this API is an internal company API (and almost certain to remain so), rather than a public facing one, influence my decision? Is there a way to get the best of both worlds?
2. I know this is a general problem connected to the principles of REST, and with many solutions (I believe Falcor is a newer approach to solving at least a similar problem). Should I be looking at other approaches?

Best Answer

Why not both?

Which is to say, yes, there are trade offs to consider, but if the marginal cost of implementing a second option is small, you can offer to your clients the ability to select which representation they prefer, so that they can choose their own trade offs (of course, there's some complexity penalty to be paid by offering a choice, rather than solving "the" problem for the clients).

The major con I see is that you've built an endpoint tightly coupled to this particular view within this particular application.

Not quite the right language, from a REST perspective. It's not the endpoint that is coupled to the application, but the media type of the representation.

Of course, worrying about media types tends to fall by the wayside when we are implementing both the client and the server, and their release cycles are coupled.

The pros of 2. are that we are using nothing but generic resource endpoints, which could be re-used by many different views and applications.

That thought is incomplete - you can not only reuse the endpoints, but you can re-used the representations themselves... ie: caching. If the client can pull the data it needs out of its own cache, then it doesn't need to round trip at all. Failing that, an intermediate cache may already have a copy of the data, shortening the round trip. The "server" that the client is talking to might be a cache farm in front of your app, keeping the workload low while being able to scale out.

In REST, you want to make sure that your designs take advantage of the uniform interface.

So one of the things you should be thinking about is the cache lifetime of your resources; how long are representations valid? Are other views and applications going to be able to take advantage of that?

Should the fact that this API is an internal company API (and almost certain to remain so), rather than a public facing one, influence my decision?

That's likely to put limits on the volume of traffic you'll need to support. Also, if the clients are all going to be centrally located, then round trip time falls away as a concern as well.

Related Topic