0

I have some REST API microservices (powered mainly with Java / Spring Boot) that communicate with other synchronously and I found out that is a bad practice since they are highly coupled.

An example

AccountAPI -> PersonAPI (create person)
           -> if personCreated then call NotificationAPI
           -> if notificationSent then call createAccount

According to the good practices, I should use asynchronous communication and/or the messaging pattern. Most of the examples talk about the notification use case where you don't need to wait for the response. I agree but this is not my case since I need the response.

Plus, using the messaging pattern is highly coupled too since I need to have an idea about the domain event to send and/or receive.

Am I wrong ? Is there any good resources with concrete examples of a use case of microservices communicating with each other and where the response is needed ?

Regards

2 Answers 2

3

I agree but this is not my case since I need the response.

It seems like in your case, you need the response to know to call the NotificationAPI. This is tight coupling, as you mentioned. In a more decoupled architecture, it would look something like this:

  1. AccountAPI broadcasts message: createPerson A
  2. PersonAPI, which subscribes to the createPerson topic, receives this event and creates the person
  3. PersonAPI broadcasts event newPersonCreated A. This is somewhat like your response, but the key is that it is telling anyone who is interested, not just the creator.
  4. NotificationAPI, which subscribes to the newPersonCreated topic, receives this event and processes it, etc.

This is less coupled because now AccountsAPI doesn't need to know anything about NotificationAPI. In fact, it doesn't even need to know about PersonAPI—simply, it declares to the message broker, "please create person A". The rest is handled via asynchronous communication. Another benefit is that if you add a new API that cares about created person events, AccountsAPI doesn't need to be changed—the new API can just subscribe to newPersonCreated events and handle from there.

Plus, using the messaging pattern is highly coupled too since I need to have an idea about the domain event to send and/or receive.

This isn't really coupling as each service has no idea about the other services that are producing or subscribing to these messages. One way to think about coupling is, "if I change X, what existing code will need to change?" If NotificationsAPI, for example, no longer cares about person events, this doesn't affect any other service—it just doesn't have to subscribe to the newPersonCreated topic! Contrast that with the request-response route, in which one would need to change the AccountAPI to no longer make a request to the PersonAPI.

However, asynchronous messaging adds a layer of complexity that absolutely may not be necessary for small use cases. It's good to follow YAGNI and understand that even though this may be helpful for larger scale applications, for small applications, it adds a layer of indirection that can be harder to maintain.

3
  • Almost, you reintroduced the coupling with the first step :-) .. API call => Create a Person => then raise a PersonCreatedEvent - subscribers react to that. Dec 12, 2021 at 23:24
  • @RobertPerry can you touch on where the coupling is and why doing a direct API call loosens coupling?
    – rb612
    Dec 13, 2021 at 3:36
  • Typically events describe "things that have happened", like 'PersonCreated' rather than 'CreatePerson' which implies a command. So, just your first point; where you're broadcasting a command to tell another service to create the 'Person' record is where we're reintroduced the coupling. I'm assuming your intention was that this is a 'command' rather than an event based on your naming convention? Therefore, direct API calls actually have the opposite effect -- increased coupling. Dec 13, 2021 at 7:18
2

I have some REST API microservices (powered mainly with Java / Spring Boot) that communicate with other synchronously and I found out that is a bad practice since they are highly coupled.

While high coupling goes against the main point of microservices. It might not necessarily be bad in itself. So I would start by asking if you have experienced any negative effects from this coupling? If not you might consider if microservices is the correct pattern for you.

There is a risk when developing microservices that there in little or no control on the amount of inter dependencies, resulting in a single request potentially resulting in a huge amount of requests between different services. And this combines all the bad parts of a monolith with the bad parts of microservices.

The main idea with microservices is that they should be independent, including development and deployment. In the given example, the Account service would not be able to do its work if either the Person or Notification service where down. This suggest the service boundaries might not be ideal.

I do not see how making a call async instead of synchronous would improve anything except save a little bit of resources, the dependency would still be there.

2
  • As soon as you couple services together - you start to lose the benefits of microservices. The answer isn't to rethink whether microservices are the right answer; its "how do I do microservices correctly to get the benefits I expect?" Dec 12, 2021 at 23:26
  • @Robert Perry I would argue that you should always consider if microservices is the right answer. That same goes for more or less all architectures and development methodologies. You should not use a pattern just because it is popular.
    – JonasH
    Dec 13, 2021 at 7:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.