Mastering Synchronous and Asynchronous API Patterns
Uncover the art of designing synchronous and asynchronous integrations with MuleSoft.
Introduction
Creating integrations using established patterns is a smart move. It keeps integration uniform, makes them easier to grasp, and simplifies maintenance. In this blog post, I'll introduce you to two widely used API Patterns: Synchronous and Asynchronous. Plus, I'll guide you through their implementation using MuleSoft and the API-Led architecture.
Problem Statement
Before starting with the patterns, architects within an organization should lay the groundwork by defining patterns for solution designers to follow. These patterns need explicit descriptions outlining when to apply them, along with their pros and cons, in order to uphold architectural uniformity. The absence of established patterns can lead to a chaotic, hard-to-maintain API-led architectures.
Solution
Synchronous Real Time API
A synchronous real-time API pattern refers to a type of communication between software applications where requests and responses are exchanged in real-time and in a synchronous manner. In this pattern, when one application (the client) makes a request to another application (the server) through an API, it waits for an immediate response before proceeding further.
Here's how the synchronous real-time APIs works:
Client Initiates Request: The process begins when the client application sends a request to the server application's API. This request typically includes specific data or instructions that the client wants the server to process.
Server Processes Request: Upon receiving the request, the server processes the data or instructions provided by the client. This processing could involve performing calculations, retrieving data from a database, or executing other operations based on the API's functionality.
Real-Time Response: In a synchronous real-time manner, the server generates a response as a result of processing the request. This response contains the outcome of the requested operation or the data that the client needs. The server sends this response back to the client immediately after processing is complete.
How to implement it with MuleSoft
There are two different approaches on how synchronous real time pattern can be implemented with the API-Led approach:
Experience-System-API: The first option reflects the left side of the diagram below. The external system, in this case Salesforce, calls the CRM Experience API which forwards the request directly to the UPS System API, by-passing the Process API because no additional logic is needed.
Experience-Process-System-API: The second option goes directly from Experience, to Process, to System API which is a common approach with the API-Led architecture, especially when there's a need for specific logic or orchestration in the Process API.
Asynchronous Near Real Time API
An asynchronous near real-time API pattern refers to a type of communication between systems where requests are made by the client and responses are generated by the server, but the client doesn't block its operations to wait for an immediate response. Instead, the client is notified of the response at a later time, allowing it to continue with its tasks without interruption. This pattern is often used when real-time responses are not essential, but timely updates are still desired.
Here's how the asynchronous near real-time API pattern works:
Client Initiates Request: The process begins when the client application sends a request to the server application's API. The request typically includes data or instructions for the server to process.
Server Processes Request: Upon receiving the request, the API publishes the message to a message queue or a topic.
Client Continues Operations: The client gets an acknowledgment response back after the message has been successfully published (or not acknowledgment in case of a failure). Unlike a synchronous pattern, the client doesn't wait for an immediate response from the server. Instead, it continues with its operations without being blocked.
Message Subscription: Another application will consume or subscribe to the message in the queue or topic.
Processing the Message: The message from the queue or topic will be further processed, this could for instance be by an additional API call to retrieve data from a database.
Response Notification: Once the server completes its processing and generates a response, the client is notified. This notification can occur through various means, such as sending an email or triggering a Webhook.
How to implement it with MuleSoft
For this scenario, it is recommended to consume / subscribe to the messages which are persisted in a messaging queue or topic by a MuleSoft Process API. In the diagram below, the Customer Process API consumes the message and processes it further to the UPS System API and SAP System API. Upon the completion of the process, a notification (for instance a Webhook) will be send back to Salesforce.
Shall the messaging queue / topic be consumed by a Process or Experience API?
It makes sense that a MuleSoft Process API consumes the messages, because this is the right place to implement a retry logic if needed. Nevertheless, there are use cases where events/messages also can be consumed by an Experience API's and I will dive into these in the next blog post about Event-Driven Architecture.
Retry Mechanism
In the context of retry mechanisms in asynchronous integrations, the terms "connectivity errors" and "data errors" refer to two distinct types of issues that can occur when attempting to transmit or process data between different systems. A retry mechanism is a strategy used to handle these errors and ensure the successful delivery of data.
Connectivity Errors: Connectivity errors stem from network or communication problems, causing issues in establishing or maintaining connections between systems. Examples include timeouts, network outages, and dropped connections. A retry mechanism for connectivity errors involves waiting for the network to stabilize and then retrying the transaction.
Connectivity Errors must be retried until the connectivity error is resolved!
Data Errors: Data errors occur due to invalid, incomplete, or incompatible data being transmitted. This is unrelated to the network but rather the content of the data. Examples include format issues, integrity problems, and validation failures. Data errors must NOT be retried and published direct to a Dead Letter Queue or an Error Topic.
Data Errors must NOT be retried as these errors will anyways fail again!
Conclusion
In integration design, maintaining consistency and manageability is essential. This post introduced two vital API patterns: Synchronous Real-Time and Asynchronous Near Real-Time. Establishing clear design patterns is crucial to prevent complexity.
In practice, a well-designed retry mechanism for asynchronous integrations should take into account both connectivity errors and data errors. It should be able to differentiate between these types of errors and apply appropriate strategies for retries. For instance, if a connectivity error occurs, the system might retry after a short delay, but if a data error is detected, the system might hold off on retries until the data issue is resolved to avoid unnecessary retries that would likely result in the same error.
It is also recommended to consider Circuit Breakers for asynchronous patterns.
What’s next?
Mastering API Design with Event Driven API Pattern
Mastering API Design for Batch Processing
Subscribe to stay up to date!