We are starting to build a new app and I would like to explore the idea of doing a thick JS client (backbone / angular) with only RESTful API exposed by our application layer. What are some of the best practices and potential pitfalls for doing this kind of web app?
3
If you are going to have only a REST API (and no actual server-side “pages”), the biggest challenges that come to mind for me are:
-
Accessibility
It’s sad, but most screen readers are way behind the times and still can’t cope with dynamic content. The modern solution is WAI-ARIA, and it’s a steep learning curve.
-
Indexing (SEO)
To Googlebot and other spiders, your site is essentially a blank page. If you need content to be indexed, you’ll have to do more than that. For truly “bare” APIs that don’t serve HTML at all, you’ll probably want to follow Google’s recommendation of using your own JavaScript-capable spider to take snapshots of pages and serve up hashbang links.
-
Cross-resource transactions
Not every workflow is going to be cleanly encapsulated by a single resource. You might need to update an /invoice and /account at the same time. There still aren’t any real standards for this; the typical answer seems to be to encapsulate the transaction itself as a resource, and handle atomicity in the REST API for the transaction resource. A shopping cart is a good example of a transaction; once you checkout, the entire basket is “committed” at once.
-
Web Optimization
You’re taking on more than 10x the amount of JavaScript that is found in more conventional web apps. All of this has to be served to the client and run at some point, so minification and performance optimization are not optional, and it can be harder to optimize the client than the server when you consider that some of your users will still be running IE8 or IE7 on Windows XP on an original AMD Athlon machine that their nephew built for them 7 years ago. Also, since you’ll be frequently changing your scripts, you can’t just minify, you also have to version, otherwise your app will mysteriously break due to caching and such.
-
Error Handling
Most back-end web frameworks have this built-in. You just hook up a global exception handler, some logging, custom error pages, and you’re done. It can be rather difficult to do this in JavaScript. You can hook up a global error handler to
$.ajax
or whatever, but even that is fraught with problems, since some error codes have semantic meaning (404, 409, etc.) Assuming you’re even willing to go to the effort of setting up a logging API to collect errors, you’ll have to make a trade-off between verbosity and bandwidth, and also put some kind of security or rate limiting on it so that people can’t just spam your logging API to DoS your site. -
Testing
At least in my experience, testing becomes more difficult because you need to maintain parallel suites of unit tests for client and server. If you do browser-based integration testing, it will be harder to tell if the failures are coming from the client or server side, unless you also maintain another suite of API-only integration tests. Basically, it’s like adding another “tier”.
-
Authentication/Authorization
There are standards for this (e.g. OAuth), but they’re a pain to implement compared to more traditional models. This is especially true if you’re running a mixed HTTP/HTTPS site and have to deal with crap like CORS. It’s very much a solvable problem and lowest on my list for a reason; it’ll just be extra work and bite you at odd times, because many of the back-end frameworks can be a bit… imperious about how authentication is supposed to work, and over-utilize things like session state.
Also, your app is basically spilling its guts to everyone who uses it, making it trivially easy to reverse-engineer the API, so you’d better make sure you have lots of validation in place, otherwise any random script kiddie can 0wn you. Not that this is a new problem, you’re just making it a little easier for them by providing a direct line.
All that being said, these are not even close to being showstoppers. Aside from the vastly improved user experience, you gain huge benefits from this model through reusability and separation of concerns. It becomes much harder (and much less necessary) for developers to abuse session state or other temporary data. And you can truly have front-end and back-end specialists, rather than having to expose your back-end guys to markup or your front-end guys to controllers.
I very much prefer this architecture but do be aware of the trade-offs you’re making. It’s still kind of a new/immature field – and people are still making a lot of mistakes. I wouldn’t trust any “best practices” guide this early in the game.
1