API Principles
Darshika Srivastava
Associate Project Manager @ HuQuo | MBA,Amity Business School
Experience API Principles
Principle 1: Experience APIs should be channel-agnostic.
The API should provide a consistent experience across all touch-points of the customer journey. It should not tailor the content to any specific device or channel. That is the job of a BFF.
Principle 2: Experience APIs should cover a customer journey, not a business capability.
The API should focus on the customer’s end goal. It should help customers achieve their desired outcome. Anything else, like internal business capabilities, are outside their scope.
Principle 3: Experience APIs should have a well-defined boundary.
The API should have a well-defined purpose. It needs to have a clear boundary with a start and an end to the journey. Because customer journeys are often interconnected, the boundary of Experience APIs needs to be designed deliberately.
Principle 4: Experience APIs should be self-sufficient.
The API should encapsulate exactly one experience. It’s a design smell for one Experience API to call another directly. This might be indicative of an insufficient journey boundary. To look at it differently, BFFs shouldn’t call more than a single Experience API to construct one customer journey.
Experience API Patterns and Anti-patterns
Arriving at a sensible service boundary starts with understanding the role and responsibility of any API. Experience APIs can take on different responsibilities and patterns.
The Aggregator Pattern:
Aggregator APIs reach out to other APIs (often in parallel) to stitch their results together and return the result back to their caller.
Experience APIs commonly play the aggregator role. The “Browse” Experience API from earlier may call Domain APIs such as Menu, Restaurant, and Offer. It then aggregates their results and stitch them together in a meaningful way to customers. Here is a diagram to illustrate this flow:
Anti-pattern: Anemic Services
Anemic services are void of meaningful behavior and rules. They may seem like legitimate experiences at first. But, in reality, they are simple features masquerading as a bounded customer journey. Here is how to recognize this anti-pattern:
While the Aggregator pattern is common, it may bring the tendency to build anemic services.
For instance, one could inaccurately think of the “Browse” Experience API as a single end-point merely wrangling data together. But this will incur the overhead of a new microservice with limited benefits. Part of the Experience should include capabilities for searching, filtering and sorting based on many attributes such as: Price Range, Ratings, Dietary restrictions, Delivery time, etc.
These filtering and sorting capabilities may also need to be dependent on Order Type (Delivery, Dine-in, Pick-up). For instance, we may not need to show “Delivery time” as a filter/sort capability if the customer is trying to order Pick-up. This shouldn’t be left to client-side logic.
If in doubt on whether to build an Experience API with shallow functionality, it’s best to wait. When a journey naturally emerges down the road, harvest it into an Experience API in the architecture.
The Orchestrator Pattern:
Orchestrator APIs coordinate other API calls (often in sequence) to the rest of the system. They are also responsible for unwinding calls should things go wrong.
Experience APIs may orchestrate calls to different services in some scenarios. For instance, a Shopping Bag Experience API allows customers to:
In the checkout scenario, we may notice the following sequences to our journey:
Here is the corresponding diagram:
Anti-pattern: Tightly-coupled Services
While orchestration is common in microservices, it can lead to tight coupling.
A common pitfall here is that orchestrator services can become a tangled mess of calls over time. Without careful consideration, we end up with “what’s another service call” implementation. Over time, orchestrator services become coupled to more services. This hampers the ability to decouple the architecture later.
Orchestrator services need to be bounded around the calls they make to other services. Notice, for example, that orchestration in the Shopping Bag happens at the end of the Experience; checkout. This is a deliberate decision that highlights where the seams are for the Experience API. A hand-off point, if you will.
领英推荐
The Event Collaborator1 Pattern:
Event Collaborator APIs coordinate communication with other APIs by listening and responding to events. They coordinate communication without needing to know of other APIs. They only know about events of interest.
Experience APIs can take part in event collaboration to manage their own state and validations. This allows them to be independent without knowing about other services. Minimal dependencies means loose coupling, which means independent deployment — the target for microservices architecture.
Let’s take a look at an example. After customers place orders, their reward points are accrued. This happens via Domain APIs such as Order Management API and Rewards API. These orders are now part of customers’ Past Orders, an Experience API, so they may re-order them again in the future.
Here is a diagram of how events can construct the state of the Past Orders Experience API.
Here’s the flow:
This flow happened without services knowing about each other’s existence. They only needed to know about the event Orders Topic.
In this case, we’ve separated the business rules from the customer experience. The business rules here encompass how the Order transitions from Submitted to Fulfilled. The customer experience is being able to view, search, download/email receipts, re-order, favorite and rate Past Orders.
But we’ve introduced data duplication by going this route. Order data is now duplicated in Order Management and Past Orders APIs. While this can be a sticking point for some, it’s a better alternative since it reduces coupling between services. Disk space is cheap and cloud storage services are a dime a dozen.
This duplication also gives finer control over data models. Now we can store and retrieve data in the most optimal way. As an example, we could serve data more quickly by caching the top 5 most recent orders for each customer.
Anti-pattern: Events-only Microservices
While there is tremendous value in pure event-driven systems, they introduce challenges. One of the challenges is that they aren’t always linear. They happen asynchronously. This makes them more complex to debug as the number of events increases. The response can vary depending on the event’s timing, order, and context.
These challenges need advanced expertise in testing systems effectively. Writing automated tests that cover all possible scenarios and edge cases can be challenging. For one, events can happen out of order. And, two, the attention shifts away from ensuring other services were called properly to ensuring certain events happened in the right sequence. While not difficult per se, it requires a mental shift and deliberate practice to be proficient.
Depending on the context, a combination of event-driven communication and orchestration can produce a flexible, cost-efficient, and easy-to-implement system.
A Hybrid Pattern:
Experience APIs can also play more than a single role within the constraints of their boundary.
Consider the example of Shopping Bag Experience API discussed before. Besides being an orchestrator, the Shopping Bag API keeps track of different customer bags as state. This enables stickiness across channels. Customers can start a bag on a web browser and pick up where they left off on a mobile device.
Personalized content and offers are another benefit here. They can persist regardless of the channel or device customers are using. This creates a sense of continuity and familiarity for customers. And, as a result, it improves overall customer satisfaction and loyalty.
Without this Experience API, this seamless movement across channels will either be missing or channels will have to constantly sync their state from other APIs.
Anti-pattern: Bloated Services
Bloated services become excessively complex or overloaded with unnecessary features. Experience APIs on this hybrid pattern may bring tendencies to cram more functionality into the service. Because they can have many responsibilities, they are often coupled to too many dependencies. Any minor sign of clutter will invite more clutter. This eventually leads to services getting bloated over time.
Ensuring that the experience is self-sufficient and bounded can help avoid this anti-pattern. It’s critical to maintain a clear understanding of the service’s purpose and only include features that align with that purpose.
Design Considerations
Latency
A common concern with Orchestrator or Aggregator Experience APIs is that they add latency. This is a fair concern. It needs evaluation on a case-by-case basis. That said, the benefits of shareable Experience APIs usually trump the minimal latency they may add. If we find that latency has a significant performance impact, here are some routes to explore:
Security
Designing any API requires thinking about its accessibility and security. Is it Public, Internal or Private? Does it handle sensitive financial data (PCI), personal or medical info (PII or EMR)?All these questions inform security design in the architecture.
Separating Experience APIs from Domain APIs adds layered security in the architecture. Since Experience APIs surface customer journeys across different channels, they can either be public or internal depending on the sensitivity of the data they process.
Domain APIs can be internal with no public access. Meaning, only services within the platform can call them. Other Domain APIs may need stricter rules. For instance, if they handle sensitive data (i.e: PCI), they may need to be private. This means that only an allowed list of services can call them. Here is a diagram to illustrate this security segmentation:
Closing Thoughts