The Architecture Pitfalls that Haunt Me
How to stay sane as an API dev supporting multiple clients…

For the last four years, I’ve helped build a NodeJS API that supports an AngularJS, iOS, and Android client. While we do our best to keep most of the logic in the API, having to support three platforms across multiple build versions can lead to some interesting frustrations.
Here are a few of the things that haunt me the most, with a dash of insight into how we try to deal with them. 👻
Table of Contents
“Can’t the API cover for this bug?”
Whether it’s long approval cycles or a dev on vacation, there will come a day when the API needs to cover for a client bug. The first time this happened we had no solution, and we spent the day scrambling to patch our iOS app and get it urgently approved by Apple.
Now we 🎉 require clients send platform & build number 🎉 information on every request. This allowed us to do a variety of wonderful things, such as:
- Quickly release a client fix by manipulating data on a specific platform and build number, until the client could release their own fix.
- Inform the clients that they need to force upgrade their builds.
- Track additional analytics on app usage per request cycle.
- Identify when certain API routes are truly decommissioned so we can start the process of deprecating older functions.
It was pretty trivial to get the build numbers of both mobile clients and we ended up converting the AngularJS package.json version into a decimal so we could perform some comparative logs. I know do this for every API and wish I had done it since day one.
“Oh, every client built that slightly different?”
It took me a long time to realize this, but communicating with a lot of people on a project is hard! Even with the best documentation, requirements, and PMs, something will get missed. Additionally, no developer wants to be babysat on the exact implementation of their code but you need the clients to basically build the feature in the exact same way.
There were more than a few occasions where I promised an “easy data update” for the API only to realize one of the clients couldn’t support the edge case and my dreams would be shattered.
Now we always 🎉 perform graceful degradation and garbage tests 🎉 for new API features being implemented by clients. Here’s an easy example of what we test each time:
- Can each client perform the primary task (render a form from an array of JSON data with types
INPUTandSELECT) - Can the client gracefully ignore fields it doesn’t know (garbage test it by sending it JSON data with types
GARBAGEandTEST) - If non-essential, can the client just continue if the API data is too unknown to even perform basic
INPUTandSELECTfunctionality?
Taking a half day to implement these tests on the API side saves us weeks of headaches in the future. It also gives you these benefits:
- You can add new type
CHECKBOXand your old app builds still work! They’ll just ignore it and still show the older fields. - If the configurable data somehow messes up, you can feel more confident that the clients will keep chugging along, then you can solve the bugs in the backend without your customer service getting bombarded.
“Can we add more of those?”
It feels like an unwritten law that I keep forgetting, but as soon as we add one item, someone will imedately want two or three more.
Take for example, when we added parent data to our user collection. At the time, I wasn’t thinking about scale, and I added a simple parent sub object. It only took a month until someone asked if we could save multiple parents per user. Apparently a lot of people have more than one parent…
So nowadays, we just 🎉 make everything an array 🎉. Any time we even remotely think a piece of user data will need more than one item, we send it stubbed as an array to our clients. This can apply to a variety of things like:
- addresses and parents
- purchase attempts and last logins
- puppies that the user loves
It’s then a quick API fix to add more entries to your sub objects. Of course this goes back to the previous point of graceful degradation and garbage testing. Make sure your clients were prepared too!
Let’s Recap
If you take anything away from this article, I hope it’s that I’ve made a lot of dumb mistakes. Hey, that’s programming! There are of course a lot of learned lessons I’m not mentioning and I still have a lot to learn, but let’s recap the lessons for today.
- Require clients to send platform and build number information
- Perform graceful degradation and garbage tests
- Make everything an array
Let me know your tricks and remember to be kind in your coding!

