Microservice gateway and access patterns
As part of my API consulting engagements, I’m often asked to review their approach to microservice architecture. While most organisations agree the goal for a microservice-based approach is to move faster and reduce team coordination through smaller services that do one thing well, not all of them agree on how they should be designed, accessed, and shared.
I have captured three common approaches these organisations use for designing and sharing microservices. Let’s look at each one and identify how they work, their advantages, and some of the challenges encountered that your organisation should avoid.
Approach 1: Direct request/response microservices
In a direct request/response model, all microservices are made available for consumption, typically via HTTP using REST constraints. The services are grouped into a bounded context to address the specific concerns, making it a little easier to discover the service(s) they need.
While this simplifies the integration of microservices for consumers, it does have a serious drawback: a fragile system that often has more limitations than a traditional modular monolith. Since consumers are directly communicating with microservices, the microservice is more difficult to evolve over time without breaking consumers. Over time, microservices become API products – albeit smaller ones.
This is considered an anti-pattern for all but a few situations. Use this approach only when the service count is low and consumers are known/easily accessible (e.g. for an early-stage startup or a SaaS moving from a monolith to microservices). As the number of services grows, the tight coupling between consumers and microservices may result in more coordination between teams rather than reduced coordination thereby slowing down teams.
Approach 2: Message-oriented microservices
To overcome the drawback of a request/response approach, an alternative is to move to a more asynchronous access pattern using a message-oriented access style. This prevents tight coupling directly to microservices as microservices may be upgraded or replaced easily, as long as the message format doesn’t change.
In this style, messages are submitted to a message queue directly, or via an API that returns a 202 Accepted response with a link to check the status of the request. One or more microservices listen for messages, process them in turn, and then emit messages containing business events as the result.
Organisations using this style have experienced a more evolvable architecture as a result of the loose coupling between consumers and microservices. The biggest advantage is that new microservices can be brought online to replace older ones, without the knowledge of the consumer. The reduced coordination between producing and consuming teams helps to maintain a higher velocity of delivery.
Additionally, consumers have the flexibility to use one or more of the following interaction patterns, as needed: consumers that fire-and-forget, fire-and-listen for events, or fire-and-follow-up using the provided response URL. The downside is that consumers may have a more complex interaction than a standard request/response approach.
However, this style does introduce additional complexity over a request/response approach. Both microservice providers and consumers must learn to code that supports this asynchronous interaction style. Testing can prove to be more challenging as well, since it may be more difficult to validate expected behaviour compared to request/response style microservices.
Approach 3: Experience APIs with microservices
For complex solutions or for large-scale development teams, a popular approach is to first define the external API contract, known as the experience API. The API is then decomposed into one or more microservices, which may consist of request/response and/or message-based approaches as necessary. The experience API performs simple orchestration logic between one or more microservices to meet the needs of internal and external apps. Typically, an experience API represents a bounded context and hides the microservices within the boundary. This is sometimes thought of as an aggregate within a domain-driven design (DDD).
While more complex to manage, this approach is by far the most flexible. Microservices are able to evolve, split into smaller microservices, or be completely replaced without negatively impacting consumers. Experience APIs adapt to the internal changes without the knowledge of consumers using the experience API. The only caveat is that the experience API must remain the same or not introduce breaking changes.
API design first techniques are used to design the experience APIs used by internal and/or external developers. Internally, these APIs are decomposed into one or more microservices that fulfil the needs of the API. A large-scale organisation may have 10s to 100s of these experience APIs that are composed of 100s to 1000s of microservices behind-the-scenes.
For a deeper look at this approach, refer to Chris Richardson’s excellent article titled “API Gateway” that covers this concept of experience APIs.
Selecting the right approach for your platform
The goal for microservices is to enable a higher velocity of software delivery for complex systems by reducing the coordination cost of teams working in parallel. Microservices are designed to grow, split, and evolve quickly. Compare that to APIs, which should evolve carefully and without creating breaking changes to downstream consumers. Selecting the right approach for your microservice-based platform is important.
I have outlined three approaches common across a variety of organisations spanning multiple business domains that vary in size from hundreds to 10s of thousands of developers. If you are uncertain where to start, start small with simple request/response or message-oriented microservices. Layer in an API gateway for flexibility and security when needed. For larger organisations, consider applying the experience API approach to provide the most flexibility.
Speaking of Microservices… It can also be challenging to establish an initiative to create APIs and microservices within your organisation. But what happens when the initiative catches on and your teams start to produce a large number of APIs and microservices? Read our blog to find out more.