API Pattern of the Week: Embedded Entity
The next two patterns we will discuss in this series are for reference management: Embedded Entity and Linked Information Holder (next week).
Olaf Zimmermann approached me a few years ago and asked me what a typical design problem I faced when implementing APIs was. I answered that I often struggle with whether to include certain data elements in a response or provide a link to them. The result of this discussion is the two patterns, and that's how my journey into pattern writing started.
Context
The information required by an API client contains structured data. This data includes multiple elements that relate to each other in certain ways. For instance, a master data element such as a customer profile may contain other elements providing contact information, including addresses and phone numbers. A periodic business results report may aggregate source information, such as monthly sales figures summarizing individual business transactions.
Problem
How can one avoid sending multiple messages when their receivers require insights about multiple related information elements?
Forces
A general rule of thumb in distributed systems is that request and response messages should not be too large so that the network and the endpoint processing resources are not over-utilized. That said, message recipients might like to follow many or all of the relationships to access information related to the requested elements. If the related elements are not included, information about their location and content and access information is required.
Solution
For any data relationship that the client wants to follow, embed a Data Element in the request or response message that contains the data of the target end of the relationship. Place this Embedded Entity inside the representation of the source of the relationship.
Example
Lakeside Mutual, a microservices sample application we developed, contains a Customer Core service aggregating several information items in its operation signatures. An API client can access this data via an HTTP resource API. This API contains several instances of the pattern. Applying the Embedded Entity pattern, a response message might look as follows:
Recommended by LinkedIn
GET http://localhost:8080/customers/a51a-433f-979b-24e8f0
{
"customer": {
"id": "a51a-433f-979b-24e8f0"
},
"customerProfile": {
"firstname": "Robbie",
"lastname": "Davenhall",
"birthday": "1961-08-11T23:00:00.000+0000",
"currentAddress": {
"streetAddress": "1 Dunning Trail",
"postalCode": "9511",
"city": "Banga"
},
"email": "rdavenhall0@example.com",
"phoneNumber": "491 103 8336",
"moveHistory": [{
"streetAddress": "15 Briar Crest Center",
"postalCode": "",
"city": "Aeteke"
}]
},
"customerInteractionLog": {
"contactHistory": [],
"classification": "??"
}
}
The referenced information items are all fully contained in the response message (e.g., customerProfile, customerInteractionLog); no URIs (links) to other resources appear. Note that customerProfile embeds nested data (currentAddress, moveHistory), while the customerInteractionLog is empty in this exemplary data set.
Discussion
➕ An Embedded Entity reduces the number of calls required: If the required information is included, the client does not have to create a request to obtain it.
➕ Embedding entities can reduce the number of endpoints because no dedicated endpoint is required to retrieve some information.
➖ Embedding entities leads to larger response messages which take longer to transfer.
➖ If the embedded entities change at a different speed (e.g., a fast-changing transactional entity refers to immutable master data), retransmitting all entities causes unnecessary overhead.
Have a look at the book for a detailed resolution of the pattern forces. Also, see the Extract Information Holder and Inline Information Holder refactorings from our Interface Refactoring Catalog of API refactorings and related architectural refactorings. Figures 1 and 2 show a message exchange with Linked Information Holder and Embedded Entity, respectively. The refactorings provide step-by-step instructions and hints on switching from one implementation to the other.
The "API Pattern of the Week" series here on LinkedIn featured the following patterns: Wish List, Pagination, Error Report, API Key, Processing Resource, Information Holder Resource, Data Transfer Resource, State Transition Operation, Metadata Element, and Id Element.
Find the complete pattern description in Chapter 7 of "Patterns for API Design," for instance, at InformIT. There is a 35% discount on the book with code API-PATTERNS.
Nice to see how the overall design picture and the relationships between the patterns become clearer every week! Some humble feedback: this pattern might challenge the Datensparsamkeit principle (see Pagination pattern: https://www.garudax.id/pulse/api-design-pattern-week-pagination-olaf-zimmermann/) for which the Wish List pattern can be applied: https://www.garudax.id/pulse/api-design-pattern-week-wish-list-olaf-zimmermann/. Another option to overcome the modelling dilemma between embedded entity versus link is to provide an 'expand' query parameter in the API. The API client would then be able to add embedded property data to a response. So in the provided example above, the 'customerInteractionLog' could be responded back as a Link Information Holder by default. In case the client wants to embed this info directly in the response, the following command can be used: GET http://localhost:8080/customers/a51a-433f-979b-24e8f0?_expand=customerInteractionLog. Many thanks for sharing this pattern and good to know what the next weekly pattern will be 😀!
in/out decisions for related data parts as conveyed by this pattern and its Information Holder Link alternative arguably have to be made in each and every #apidesign Published Language from #DDD in Action!