DONT Use REST for Microservices, OK?
Founder of Moodio.co.uk - High performance software development services
You shouldn't be using a REST or RESTful interface for communication between your microservices. I'm not saying that to be controversial, I'm saying it because that's not what REST was designed for, it's not what REST is good at and it's definitely not the best nor easiest option out there.
Do You Even Rest Bruh?
Firstly, and most importantly, you're most likely not even creating REST interfaces. REST has a LOT of rules and the specification can be fuzzy at times, but most API interfaces out there that claim to be REST are more likely "RESTful". And RESTful is just a term made up by people who needed to put something in their CV to make it seem like they kind of knew about REST without really needing to learn anything about it or ever actually have to implement an interface that adheres to the REST interface.
Luckily however the people recruiting them, interviewing them, and the ones they're going to be working with all most likely don't really know much about REST either, so RESTful just sort of stuck around, and people continued to act like they were building REST-"ful" interfaces, had debates cantered around whether or not you should use a PUT, PATCH or POST to update a record, and continued on their merry way with an extra bullet point on their CV.
What you most likely are using is JSON on top of the basic, standard HTTP protocol, and possibly not even using that well. Ironically however, JSON isn't part of the REST specification, you can use a whole bunch of other formats too.
REST is Designed for (Semi-)Public, Discoverable, Human Readable Services
The fact that REST is designed to be human readable should be the first giveaway that it's not designed with service to service communication in mind, but did you know REST was also designed to be discoverable and that using a single top level API endpoint you should be able to traverse and discover the entirety of the API, without any documentation?
These are all things that are useful in public or semi-public services, but are mostly useless in microservices. Your microservices should have absolutely zero requirements to be human readable or discoverable. If you feel like they do, then you more likely have an issue with internal communication between teams then anything else, something which REST was not designed to solve.
REST is Slow
I'm pretty sure that when you were sold the vision of microservices you weren't also sold the idea wasting time and CPU resources parsing an object, to text, only to collect it on the other side as text and back to an object.
But if you're using REST for communication between micro-services, that's most likely what you're doing. It's slow. Sure in human time a few milliseconds aren't that bad, but when you do this several times for each interaction an end user makes, and do it thousands or millions of times a day, it really builds up and takes a toll.
It's slow because it wasn't designed to be used thousands or millions of times a day, it was designed to be used once during a single API call at the edge of your system and to an external system that is not in your control.
REST is Never Native
“If you try to please everyone, you’ll end up pleasing no one.”
Part of the reason no one learns REST is because it's not native to any programming language, framework or development style commonly used (Or atleast not anyone I've ever come across). It follows its own patterns, its own style of organization and you always feel forced to compromise if you want to fit your own interface into the requirements of REST.
To a software engineer for whom half their life is about making sure you have the cleanest design patterns, it just often feels wrong and makes you feel a little dirty. It's enough to make anyone just want to get it over and done with as quickly as possible before switching back to the more wholesome parts of you code.
SOAP Leaves a Bad Task in Your Mouth
When she was good, She was very good indeed, But when she was bad she was horrid.
And finally, one thing to remember, is that REST gained popularity at a time when the main alternative would have been SOAP and your standard RPC protocols. Now while REST is (IMO) bad for microservices, SOAP was worse! Not because of the technology, that it was implemented poorly or that it wasn't heavily supported and invest in, quite the opposite, it was actually a pretty good framework, well engineered and had support from the tech heavy weights of the time including Microsoft, IBM and Oracle.
Instead however, its development and the development of protocols which were built on top of SOAP, such as WSDL and WS-Secure, were developed in a way that was somewhat similar fashion to how the web specifications was. Each vendor had their own interpretation of what the specifications meant, which protocols to even support and in most situations the differences, though small, made for an extremely frustrating experience.
This was made all the worse that SOAP and WS-* protocols weren't really made to be human readable and relied on tools built by the vendors to generate libraries which you would use in your own software. So when something went wrong, basically there was not much you could do about it.
As such many people just ended up hating SOAP and the entire suite of WS-* protocols, deciding to just hand-build the own interfaces using REST as they see fit. And when everyone realised that even REST too much effort, RESTful was born!
Not Every Operation Should Be Synchronous
In micro-services, one of the most hyped benefits is that the resilience that comes by splitting out a monolith into separate services. Sure, if it's implemented correctly that can definitely be the case, but if you're using REST, then most likely you're relying on synchronous messaging, i.e. When a service calls another service, it waits for the reply before return the results to it's own caller, in which case not only have you just made your application slower at the best of times, you've made sure that any single service suffering from performance issues will bring down ever other service that calls it with it.
Quite frankly, if you're creating a micro-service based architecture where all operations are synchronous, you probably should be using a different architectural pattern, and if you are using asynchronous patterns, then you should be using a different interface, such as a queue or pub/sub patterns where you can either request and forget, and create a callback for when an operation is completed without having to wait for it.
There Are Alternatives
Most importantly though is that there are many superior alternatives for different use cases, those that are simpler, faster and can be developed in a pattern that is consistent with the design patterns native to your own chosen language and framework.
One of the best options out there would be RPC and RPCful (lol) protocols such as gRPC
for synchronous operations or RabbitMQ
for queue based and pub/sub type operations. Unfortunately, and quite possibly most likely due to SOAP, RPC protocols have a bit of a bad reputation, however for microservices in particular they are a very good fit. They are designed for distributed systems and are often either faster (with gRPC using http2 and sending data in a binary format) or better for asynchronous operations and splitting them between different services which is the case with queues.
gRPC in particular is also far easier to implement with clients implemented as native classes making using external services nearly indistinguishable from using any other object in your system.
So stop making your life more difficult then it needs to be and do yourself a favour and go follow the 1 page tutorials thats available on the gRPC or RabbitMQ website, add 2 new bullet points to your CV and give REST a rest (😊) when it comes to service to service communication.
Subscribe to get your daily round-up of top tech stories!