27

I'm working on a new iOS app project, on the mobile side. Some architecture changes are happening and it turns out we will have to rely on a custom built private API that will be used by the app we are building and also by other clients such as a website.

The API being designed follows the Rest style of resources-centric URI and CRUD operations mapped to HTTP verbs. things like:

GET www.example.com/books
DELETE www.example.com/books/482094
POST www.example.com/users/6793

The problem is that this style often leads to the need for the mobile client to do many requests for loading a single app screen or managing a single user UI action. This leads to the app being in loading mode for 8 seconds till it has everything needed. A slow and unresponsive app.

Mobile clients have serious limitations when it comes to connectivity and so ideally, we should follow that sort of rule:

1 screen == 1 API call

1 save == 1 API call.

There are many situations where this puts you on a collision course with the REST design principles, for examples:

  • let's say your app has been offline for a day and you need to sync with four tables of the back-end databases and you need a call like www.example.com/sync_everything?since=2015-07-24
  • let's say there is a screen where the user can edit many of his objects, for example ticking tasks in his todo list. There should be a way to edit all those tasks records in one single batch API call rather than one API call per edit.
  • let's say there is a screen that mixes information from the ORDER, SALESMEN and PRODUCT db tables, I should get that data in one call instead of three.

the risk is that we might end up with the most Restful API there is and also the most useless unresponsive mobile app there is.

The thing is I'm only a new contractor there and what I need is something that help me makes those points, some articles from well respected sources or something like that. Major players compromising with the REST style for their mobile client (e.g.: by using composite aggregate API end points).

Or any solution for this general problem. Thanks!

8
  • 3
    It sounds like your question might be, "How can an API deliver collections of objects and embedded objects of like or unlike types while retaining the REST style?" Am I understanding your question?
    – joshp
    Aug 8, 2015 at 17:49
  • I believe the general answer is that each REST call needs to take a variety of optional parameters so it can be flexible yet still relatively intuitive. The syncing case will always be tricky, but for regular pages you are normally looking at several calls of the same type, i.e. all GETs, right?
    – Ixrec
    Aug 8, 2015 at 17:50
  • 1
    I think adapting your API is the wrong solution when the problem is the lack of parallel requests – 8 small requests are not much worse than one large request when they don't have to wait for each other. Can you switch to HTTP/2? Or at least use HTTP/1.1 pipelining?
    – amon
    Aug 8, 2015 at 18:58
  • See also: Patterns for handling batch operations in REST web services?. The key is identifying what kinds of commands (and under what preconditions) can be batched together without conflicts, and then create a JSON representation of the batched order, and then sending it over. It loses the main attractiveness for REST which is its cacheability but cacheability isn't always relevant for all kinds of applications. Note that batch/concurrency isn't applicable if there are logical dependencies.
    – rwong
    Aug 8, 2015 at 20:38
  • An analogy for the situation where the middleman needs to perform multiple operations in a sequence, with non-trivial logical dependencies on each preceding operation, is something like "stored procedure", that is executed in that middleman instead of inside a database. Underneath, the middleman is allowed to convert a single "stored procedure" call into as many RESTful requests as needed, but that is an implementation detail of the middleman.
    – rwong
    Aug 8, 2015 at 20:41

1 Answer 1

30

The API being designed follows the Rest style of resources-centric URI and CRUD operations mapped to HTTP verbs.

This is your problem right here.

You have limited your resources to (I'm assuming) the models in your database. As such it is taking ages to load all these resources because your server has no concept of resources that don't have a representation in the database.

For example might have

www.example.com/books/482094
www.example.com/books/582045
www.example.com/books/427454
www.example.com/books/319343

that all have to be loaded to get my library

This isn't a problem with RESTful design, this is actual a REST anti-pattern. There is absolutely nothing in REST that says our resources must have a one to one mapping with anything else in your system, including database models.

The solution is to create more resources that better match what you want to load. If you have 5 resources that always end up together create a new resource that contains the info for those 5 resources.

What you should have is something like this

www.example.com/users/334/my_library

which just loads all the books for that user. "my_library" isn't a model in your database, but it is a resource. The server creates it based on models in the database but there is no 1-to-1 mapping and the server has flexibility to create this resource without changing your DB model.

You might also have

www.example.com/users/334/favioured_books
www.example.com/users/334/books_ordered_last_week
www.example.com/users/334/wishlist

none of which have to exist as model in your database or domain space.

There is a wide spread misconception that this is the wrong thing to do because frameworks like Rails taught people to map resources in a 1-to-1 fashion to models in the domain space which map again 1-to-1 with database rows. This is not necessary nor is it recommended.

Resources should be numerous, cheap and lightweight. It should be easy to create them, and they should be abstracted from your domain model. If you find you need a new one you just make a new one. If you have problems doing that it is your frameworks fault not a fault with REST.

Now the big caveat with that of course is whether your framework allows you to do this. Frameworks like Rails and Django which have taken the course to map 1-to-1 in order to "save you time" make it hard to do this. But that is a flaw with the frameworks, not with RESTful design.

Here is Jim Webber discussing this is more detail (including a few digs at Rails as well!)

https://yow.eventer.com/yow-2011-1004/domain-driven-design-for-restful-systems-by-jim-webber-1047

3
  • This is very interesting and I fully agree with this but sadly, I'm not the one doing the API and I have little way to influence it, if any. Many people will use that "anti-pattern" all over (for many reasons, framework limitations being one) and they just use the URI definition for thinking clearly about their database. The API endpoints are just another way to visualise their DB... Also, in some cases, creating a resource such as the one you described is difficult due to the fact objects are really different, just naming them would lead to very vague terms.
    – MikaelW
    Aug 25, 2015 at 10:50
  • To go back to the issue from an efficiency angle, they agreed that if a mobile screen is very slow (and only if this happened), there will be some composite calls possible but they will be sitting in a component that wraps around the API (rather than the API itself), will only be used by the mobile clients and won't be considered as part of the core API, the core domain.
    – MikaelW
    Aug 25, 2015 at 10:51
  • @MikaelW, you are right. Even what Cormac said is the ideal scenario, some times you are working with an API that needs to attend a lot of other systems (desktop, mobile, web, scheduled jobs, legacy systems, etc). This kind of API needs to be really flexible, providing resources to attend many possibilities as possible but can't attend all specific performance necessities from one consumer. In that case you don't have many choices...
    – Dherik
    Apr 9, 2018 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.