APIs and microservices do indeed have a lot in common. Microservices are capabilities exposed via standard network protocols, most commonly HTTP. But capabilities exposed as HTTP endpoints had been known as web APIs, way before the coining of the term microservices. So are the two essentially the same thing? Are microservices just a new flavor of APIs — smaller APIs? More importantly, do we even need conventional APIs once we start writing microservices, or do the smaller APIs (microservices) replace the bigger (conventional) APIs? We have often seen these questions cause a lot of confusion on teams trying to adopt a microservices architecture.
With some frequency, we have encountered developers referring to any small, focused APIs as “microservices.” In such an approach microservices have the same role as APIs had before them, so they do indeed replace the APIs of old. In our experience, this is not an ideal approach for successful microservices thinking, and we offer an alternative, albeit opinionated, definition of what separates microservices from legacy APIs. Our approach builds on the experience of some notable experts in the space and is rooted in our own experiences with successful microservices projects and teams.
Microservices Are Not Just Smaller APIs
Microservices are not just smaller replacements for the APIs of the old days. Microservices provide the implementation of your system, while APIs should still be the outward-facing interface of a system.
We think that if microservices replace anything, the things they replace are the modular components you used to build your systems with. If before you would build a large system by linking (statically or dynamically) various submodules together, in a microservices architecture the building blocks are networked services we call “micro-services.” This approach is depicted in Figure 3–5.
There is no one, true way of organizing microservices and connecting them up with “frontend” APIs. This is the part where we live up to the promise of providing unabashedly opinionated guidance in this book. Our opinions are rooted in what we have witnessed to have worked well, but we also acknowledge that other strategies may have worked for other practitioners.
In our experience, the ideal separation of duties happens when all of the business logic (capabilities) is implemented by microservices, while APIs act as a thin layer of orchestration in front of those microservices. Additionally, we recommend that teams try to avoid microservices directly “invoking” each other. Instead, for the sake of loose coupling, it’s best if any orchestrating workflow is implemented in the API layer, in front of microservices, without microservices knowing anything about each other.
Note that there is no 1:1 relationship between an API and the microservices that implement the corresponding capability. These two assets are parts of fundamentally different layers of your architecture.
We believe that such “microservices should be unaware of each other and be orchestrated externally” approach is where the Unix philosophy of building a system as a collection of composable tools resonates well with microservices architecture principles. One of the most powerful aspects of the Unix philosophy is that you can combine Unix tools (e.g., GNU tools) in a variety of ways using input and output piping on the command line or in shell scripts. However, in order to achieve this, it’s critical that various Unix tools act the same way for any input — they should not care who “calls” them or where their output goes. Components cannot explicitly know about each other for them to become composable. Loose coupling is what makes the whole thing work, not just that the tools are small-ish and focused. The same holds true for microservices.
Keep Microservices Unaware of Each Other
Avoid microservices directly “knowing” about each other and directly calling each other via synchronous interfaces. Instead, try to orchestrate processes involving multiple microservices in the API layer. If this is not possible, consider using asynchronous inter‐ faces between microservices where an upstream microservice publishes data to an event log (e.g., Kafka) and a downstream microservice can subscribe to that event log without the upstream microservice having tight coupling with the subscriber(s).
This was part of my knowledge of reading the Book “Microservices up and Running.”