Understanding the Adapter Design Pattern with Real-Life Example: Integrating NetSuite and Business Central (BC) Data
When you’re working with multiple systems or APIs, such as NetSuite and Business Central (BC), you often face the challenge of dealing with different data formats and structures. These systems may return customer data with different field names, making it difficult to integrate their responses into a single database or application.
In this blog, we’ll explore how to use the Adapter Design Pattern to solve this problem in a simple and efficient way. We’ll explain the concept in a way that even beginners can understand by using real-life data from NetSuite and Business Central (BC) APIs, transforming their data to a common format that your application can easily work with.
What is the Adapter Design Pattern?
The Adapter Design Pattern is a structural design pattern that allows two incompatible interfaces to work together. It acts as a bridge, translating one interface (or data format) into another, making it easier to integrate systems that have different data structures.
Imagine you’re trying to plug a European plug into an American socket. The plug doesn’t fit, but by using an adapter, you can convert the European plug into something that fits the American socket. Similarly, in programming, an adapter transforms data from one format to another so that two different systems can work together seamlessly.
Real-Life Scenario
Let’s say you have two ERPs:
- NetSuite: A popular ERP system.
- Business Central (BC): Another widely-used ERP system.
Both systems return customer data, but their field names differ:
- NetSuite uses fields like
customerId
,name
,email
,phone
, andstatus
. - Business Central (BC) uses fields like
ClientID
,FullName
,EmailAddress
,Contact
, andCustomerStatus
.
We need to convert both of these responses into a common format so that our application can work with them seamlessly.
Our Goal
We want to standardize the data from both systems to a common schema, like this:
{
"id": "string",
"full_name": "string",
"email": "string",
"phone_number": "string",
"status": "string"
}
This common schema will be the format our application uses to process customer data.
How Do We Solve This with the Adapter Pattern?
Here’s how we can apply the Adapter Design Pattern in this situation:
- Adaptee: The two ERPs, NetSuite and BC, which provide customer data in different formats.
- Adapter: A class that adapts the data from NetSuite and BC into our required common format.
- Target Interface: A unified interface (or schema) that our application can work with.
Implementation Steps
We’ll break down the solution into manageable steps and write code to integrate both NetSuite and Business Central data.
Step 1: Define the Adaptees (NetSuite and BC)
The adaptees are the systems from which we will receive customer data. Here’s how the APIs might look for both NetSuite and BC:
NetSuite Adaptee
class NetSuiteAPI:
def get_customer(self):
return {
"customerId": "101",
"name": "Alice",
"email": "alice@example.com",
"phone": "1234567890",
"status": "Active"
}
Business Central Adaptee
class BusinessCentralAPI:
def get_customer(self):
return {
"ClientID": "202",
"FullName": "Bob",
"EmailAddress": "bob@example.com",
"Contact": "9876543210",
"CustomerStatus": "Active"
}
Both these classes represent the different ways customer data is returned from each ERP system. We’ll need to adapt them to a common format.
Step 2: Define the Adapter Classes
Next, we define the adapter classes that will convert the data from each ERP into a common format.
NetSuite Adapter
class NetSuiteAdapter:
def __init__(self, netsuite_api):
self.netsuite_api = netsuite_api
def get_customer_data(self):
data = self.netsuite_api.get_customer()
# Map NetSuite fields to the unified schema
return {
"id": data["customerId"],
"full_name": data["name"],
"email": data["email"],
"phone_number": data["phone"],
"status": data["status"]
}
Business Central Adapter
class BusinessCentralAdapter:
def __init__(self, bc_api):
self.bc_api = bc_api
def get_customer_data(self):
data = self.bc_api.get_customer()
# Map Business Central fields to the unified schema
return {
"id": data["ClientID"],
"full_name": data["FullName"],
"email": data["EmailAddress"],
"phone_number": data["Contact"],
"status": data["CustomerStatus"]
}
Step 3: Define the Client Class to Process Data
Now, we create a Client class that will use the adapter to process the customer data. This class will be responsible for calling the get_customer_data()
method of the adapter, which will return the data in the unified format.
class Client:
def __init__(self, adapter):
self.adapter = adapter
def process_customer(self):
customer_data = self.adapter.get_customer_data()
print("Unified Customer Data:", customer_data)
Step 4: Putting It All Together
Finally, we can create instances of the adapters and clients for both NetSuite and Business Central, then process the customer data.
if __name__ == "__main__":
# Create instances of the Adaptees (NetSuite and BC APIs)
netsuite_api = NetSuiteAPI()
bc_api = BusinessCentralAPI()
# Create instances of the Adapters
netsuite_adapter = NetSuiteAdapter(netsuite_api)
bc_adapter = BusinessCentralAdapter(bc_api)
# Create instances of the Client with respective adapters
netsuite_client = Client(netsuite_adapter)
bc_client = Client(bc_adapter)
# Process and print customer data
netsuite_client.process_customer()
bc_client.process_customer()
Output
When you run this script, it will print the following output:
Unified Customer Data: {'id': '101', 'full_name': 'Alice', 'email': 'alice@example.com', 'phone_number': '1234567890', 'status': 'Active'}
Unified Customer Data: {'id': '202', 'full_name': 'Bob', 'email': 'bob@example.com', 'phone_number': '9876543210', 'status': 'Active'}
Why Is This Important?
By using the Adapter Design Pattern, we’ve:
- Unified data from two different sources (NetSuite and BC).
- Simplified the integration of multiple systems with different data structures.
- Made it scalable and maintainable, allowing you to easily add more systems in the future (like SAP or Salesforce) with minimal changes.
Conclusion
The Adapter Design Pattern is an essential tool when working with multiple systems or APIs that return data in different formats. It allows you to standardize and unify that data so that your application can work with it seamlessly.
In this blog, we’ve demonstrated how to use the Adapter Design Pattern to transform customer data from NetSuite and Business Central (BC) into a common format. This approach ensures that no matter how the data is structured in the source system, your application can handle it without issues.
If you’re working with systems that need to interact with each other, consider using the Adapter Design Pattern to simplify your integration process.I hope this blog helps you understand the Adapter Design Pattern better! Let me know if you have any questions or need further clarification. Happy coding!