Let's start with the fundamental question:
Is it OK to communicate between microservices directly via REST calls?
Short answer: yes, but...
I just want to clarify a couple concepts. An API gateway is there to redirect requests to one of the potentially multiple instances of a microservice you have running. The gateway handles the load balancing, etc.
If you want direct connect between microservices, you still need the loadbalancing. It all depends on your infrastructure how you handle it. For example, the way you accomplish that with Kubernetes, Spring Cloud infrastructure, or Consul will be slightly different.
The reality is that any one of your microservices can go into a partial failure, where it ceases to respond to new requests and is essentially "stuck". It can be for many reasons like memory pressure and garbage collection gone into hyperdrive, an endless loop that didn't get caught in testing, etc.
The bottom line is:
- The more services you chain together in one call increases the chance that one of those things can go wrong
- Using a circuit breaker pattern helps mitigate the issue with stuck microservices, allowing you to fail gracefully
- I recommend using some form of Open Tracing to debug problems in this scenario
- Asynchronous calls through an message queue might greatly improve the responsiveness of your API
The sooner you can send a meaningful response to your caller, the more responsive your application will feel. There may be further processing that needs to be done, but the user doesn't need to sit and wait for everything to be completed as long as they can trust that it will be completed.
As a general rule of thumb:
- Very short duration calls from one service to another are fine. Example: an authentication service calls a user management service to find the important factors to generate a session token.
- Long duration calls from service to service are at risk of timeout. Use asynchronous communications if possible.
- If you find yourself having to make a lot of service-to-service calls, that can be a symptom that you might not have divided the responsibilities of the services appropriately.
- Avoid long service call chains (i.e. service 1 calls service 2 that calls service 3, etc.), perhaps asynchronous calls can simplify that.