AW Patterns For API Design
AW Patterns For API Design
“The authors have captured design patterns across the API lifecycle, from definition
to design, in an approachable way. Whether you have designed dozens of web APIs or
you are just starting out, this book is a valuable resource to drive consistency and
overcome any design challenge you may face. I highly recommend this book!”
—James Higginbotham
Author of Principles of Web API Design: Delivering value with APIs and
Microservices and Executive API Consultant, LaunchAny
“APIs are everywhere in today’s software development landscape. API design looks
easy but, as anyone who has suffered a poorly designed API will attest, it is a difficult
skill to master and much subtler and more complex than it initially appears. In this
book, the authors have used their long experience and years of research work to cre-
ate a structured body of knowledge about API design. It will help you to understand
the underlying concepts needed to create great APIs and provides a practical set of
patterns that you can use when creating your own APIs. It is recommended for any-
one involved in the design, building, or testing of modern software systems.”
Application programming interfaces (API) are among the top priority elements to help
manage many of the trade-offs involved in system design, in particular distributed sys-
tems, which increasingly dominate our software ecosystem. In my experience, this
book removes the complexities in understanding and designing APIs with concepts
accessible to both practicing engineers and those who are just starting their software
engineering and architecting journey. All who aspire to play a key role in system design
should understand the API design concepts and patterns presented in this book.”
—Ipek Ozkaya
Technical Director, Engineering Intelligence Software System
Software Solutions Division
Carnegie Mellon University Software Engineering Institute
Editor-in-Chief 2019–2023 IEEE Software Magazine
“It is my belief that we are entering into an era where API-first design will become
the dominant form of design in large, complex systems. For this reason, Patterns for
API Design is perfectly timed and should be considered essential reading for any
architect.”
“The book Patterns for API Design is the Swiss army knife for software engineers
and architects when it comes to designing, evolving, and documenting APIs. What I
particularly like about the book is that it does not just throw the patterns at the
reader; instead, the authors use realistic examples, provide hands-on architecture
decision support, and exemplify patterns and decisions using a case study. As a
result, their pattern language is very accessible. You can use the book to find solu-
tions for specific problems or browse entire chapters to get an overview of the prob-
lem and solution spaces related to API design. All patterns are well-crafted,
well-named, and peer-reviewed by the practitioner community. It’s a joy.”
Olaf Zimmermann
Mirko Stocker
Daniel Lübke
Uwe Zdun
Cesare Pautasso
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where
those designations appear in this book, and the publisher was aware of a trademark claim, the designations have been printed
with initial capital letters or in all capitals.
The authors and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of any
kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential damages in
connection with or arising out of the use of the information or programs contained herein.
For information about buying this title in bulk quantities, or for special sales opportunities (which may include electronic
versions; custom cover designs; and content particular to your business, training goals, marketing focus, or branding
interests), please contact our corporate sales department at [email protected] or (800) 382-3419.
For questions about sales outside the U.S., please contact [email protected].
All rights reserved. This publication is protected by copyright, and permission must be obtained from the publisher prior
to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic,
mechanical, photocopying, recording, or likewise. For information regarding permissions, request forms and the appropriate
contacts within the Pearson Education Global Rights & Permissions Department, please visit www.pearson.com/permissions.
ISBN-13: 978-0-13-767010-9
ISBN-10: 0-13-767010-9
ScoutAutomatedPrintCode
Pearson’s Commitment to Diversity, Equity, and Inclusion
Pearson is dedicated to creating bias-free content that reflects the diversity of all learners. We
embrace the many dimensions of diversity, including but not limited to race, ethnicity, gender,
socioeconomic status, ability, age, sexual orientation, and religious or political beliefs.
Education is a powerful force for equity and change in our world. It has the potential to
deliver opportunities that improve lives and enable economic mobility. As we work with authors
to create content for every product and service, we acknowledge our responsibility to demonstrate
inclusivity and incorporate diverse scholarship so that everyone can achieve their potential
through learning. As the world’s leading learning company, we have a duty to help drive change
and live up to our purpose to help more people create a better life for themselves and to create a
better world.
Our ambition is to purposefully contribute to a world where:
While we work hard to present unbiased content, we want to hear from you about any
concerns or needs with this Pearson product so that we can investigate and address them.
xi
xii Contents
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499
Foreword by Vaughn Vernon,
Series Editor
xvii
xviii Foreword by Vaughn Vernon, Series Editor
That’s where this series comes into play. I am curating a series designed to help
you mature and reach greater success with a variety of approaches—reactive, object,
and functional architecture and programming; domain modeling; right-sized ser-
vices; patterns; and APIs. And along with that, the series covers best uses of the asso-
ciated underlying technologies. It’s not accomplished in one fell swoop. It requires
organic refinement with purpose and skill. I and the other authors are here to help.
To that end, we’ve delivered our very best to achieve our goal.
Now, back to my story. When Olaf and I first met, I offered for him and Stefan to
attend my IDDD Workshop a few weeks later in Munich, Germany. Although nei-
ther were able to break away for all three days, they were open to attend the third and
final day. My second offer was for Olaf and Stefan to use time after the workshop to
demonstrate the Context Mapper tool. The workshop attendees were impressed, as
was I. This led to further collaboration on into 2020. Little did any of us expect what
that year would bring. Even so, Olaf and I were able to meet somewhat frequently to
continue design discussions about Context Mapper. During one of these meetings,
Olaf mentioned his work on API patterns that were provided openly. Olaf showed
me a number of patterns and additional tooling he and others had built around
them. I offered Olaf the opportunity to author in the series. The result is now in
front of you.
I later met on a video call with Olaf and Daniel Lübke to kick off product devel-
opment. I have not had the chance to spend time with the other authors—Mirko
Stocker, Uwe Zdun, Cesare Pautasso—but I was assured of the team’s quality given
their credentials. Notably, Olaf and James Higginbotham collaborated to ensure the
complementary outcome of this book and Principles of Web API Design, also in this
series. As an overall result, I am very impressed with what these five have contributed
to the industry literature. API design is a very important topic. The enthusiasm
toward the book’s announcement proves that it is right in the topic’s sweet spot. I am
confident that you will agree.
—Vaughn Vernon, series editor
This page intentionally left blank
Foreword by Frank Leymann
APIs are everywhere. The API economy enables innovation in technology areas,
including cloud computing and the Internet of Things (IoT), and is also a key ena-
bler of digitalization of many companies. There hardly is any enterprise application
without external interfaces to integrate customers, suppliers, and other business
partners; solution-internal interfaces decompose such applications into more man-
ageable parts, such as loosely coupled microservices. Web-based APIs play a promi-
nent role in these distributed settings but are not the only way to integrate remote
parties: queue-based messaging channels as well as publish/subscribe-based channels
are widely used for backend integration, exposing APIs to message producers and
consumers. gRPC and GraphQL have gained a lot of momentum as well. Thus, best
practices for designing “good” APIs are desirable. Ideally, API designs persist across
technologies and survive when those change.
Patterns establish a vocabulary for a problem-solution domain, finding a balance
between being abstract and concrete, which gives them both timelessness and rele-
vance today. Take Enterprise Integration Patterns by Gregor Hohpe and Bobby Woolf
from the Addison Wesley Signature Series as an example: I have been using it in
teaching and industry assignments since my time as lead architect of the IBM MQ
family of products. Messaging technologies come and, sometimes, go—but the mes-
saging concepts such as Service Activator and Idempotent Receiver are here to stay. I
have written cloud computing patterns, IoT patterns, quantum computing patterns,
even patterns for patterns in digital humanities myself. And Martin Fowler’s Patterns
of Enterprise Application Architecture, also from the Addison Wesley Signature
Series, gives us the Remote Façade and the Service Layer. Hence, many parts of the
overall design space of distributed applications are covered well in this literature—
but not all. Therefore, it is great to see that the API design space is now supported by
patterns too, the request and response messages that travel between API client and
API provider in particular.
The team who wrote this book is a great mix of architects and developers com-
posed of deeply experienced industry professionals, leaders in the patterns commu-
nity, and academic researchers and lecturers. I have been working with three of the
authors of this book for many years and have been following their MAP project since
its inception in 2016. They apply the pattern concept faithfully: Each pattern text
follows a common template that takes us from a problem context, including design
forces, to a conceptual solution. It also comes with a concrete example (often
xxi
xxii Foreword by Frank Leymann
RESTful HTTP). A critical discussion of pros and cons resolves the initial design
forces and closes with pointers to related patterns. Many of the patterns went
through shepherding and writers workshops at pattern conferences, which helped to
incrementally and iteratively improve and harden them over several years, capturing
collective knowledge as a result from this process.
This book provides multiple perspectives on the API design space, from scoping
and architecture to message representation structure and quality attribute-driven
design to API evolution. Its pattern language can be navigated via different paths,
including project phases and structural elements such as API endpoint and opera-
tion. As in our Cloud Computing Patterns book, a graphical icon for each pattern
conveys its essence. These icons serve as mnemonics and can be used to sketch APIs
and their elements. The book takes a unique and novel step in providing decision
models that collect recurring questions, options, and criteria regarding pattern
applications. They provide stepwise, easy-to-follow design guidance without over-
simplifying the complexities inherent to API design. A stepwise application to a sam-
ple case makes the models and their advices tangible.
In Part 2, the patterns reference, application and integration architects will find
the coverage of endpoint roles such as Processing Resource and operation responsi-
bilities such as State Transition Operation useful to size APIs adequately and make
(cloud) deployment decisions. State matters, after all, and several patterns make
state management behind the API curtain explicit. API developers will benefit from
the careful consideration given to identifiers (in patterns such as API Key and Id Ele-
ment), several options for response shaping (for instance, with Wish Lists and a Wish
Template that abstracts from GraphQL), and pragmatic advice on how to expose
metadata of different kinds.
I have not seen life-cycle management and versioning strategies captured in pattern
form in other books so far. Here, we can learn about Limited Lifetime Guarantees and
Two in Production, two patterns very common in enterprise applications. These evolu-
tion patterns will be appreciated by API product owners and maintainers.
In summary, this book provides a healthy mix of theory and practice, containing
numerous nuggets of deep advice but never losing the big picture. Its 44 patterns,
organized in five categories and chapters, are grounded in real-world experience and
documented with academic rigor applied and practitioner-community feedback
incorporated. I am confident that these patterns will serve the community well,
today and tomorrow. API designers in industry as well as in research, development,
and education related to API design and evolution can benefit from them.
• The context and the purpose of the book—its motivation, goals and scope.
• Who should read the book—our target audience with their use cases and
information needs.
• How the book is organized, with patterns serving as knowledge vehicles.
Motivation
Humans communicate in many different languages. The same holds for software.
Software not only is written in various programming languages but also communi-
cates via a plethora of protocols (such as HTTP) and message exchange formats
(such as JSON). HTTP, JSON, and other technologies operate every time somebody
updates their social network profile, orders something in a Web shop, swipes their
credit card to purchase something, and so on:
xxiii
xxiv Preface
API clients consume the services exposed by API providers. API documentation gov-
erns the client-provider interactions.
Just like humans, software components often struggle to understand each other
when they communicate; it is hard for their designers to decide on an adequate size and
structure of message content and agree on the best-suited conversation style. Neither
party wants to be too quiet or overly talkative when articulating its needs or responding
to requests. Some application integration and API designs work very well; the involved
parties understand each other and reach their goals. They interoperate effectively and
efficiently. Others lack clarity and thereby confuse or stress participants; verbose mes-
sages and chatty conversations may overload the communication channels, introduce
unnecessary technical risk, and cause extra work in development and operations.
Now, what distinguishes good and poor integration API designs? How can API
designers stimulate a positive client developer experience? Ideally, the guidelines for
good integration architectures and API designs do not depend on any particular
technology or product. Technologies and products come and go, but related design
advice should stay relevant for a long time. In our real-world analogy, principles such
as those of Cicero’s rhetoric and eloquence or Rosenberg’s in Nonviolent Communi-
cation: A Language of Life [Rosenberg 2002] are not specific to English or any other
natural language; they will not go out of fashion as natural languages evolve. Our
book aims to establish a similar toolbox and vocabulary for integration specialists
and API designers. It presents its knowledge bits as patterns for API design and evo-
lution that are eligible under different communication paradigms and technologies
(with HTTP- and JSON-based Web APIs serving as primary sources of examples).
While much has been said and written about HTTP, Web APIs, and integration
architectures in general (including service-oriented ones), the design of individual
API endpoints and message exchanges has received less attention so far:
• How many API operations should be exposed remotely? Which data should be
exchanged in request and response messages?
Preface xxv
The patterns in this book help answer these questions by sketching proven solu-
tions to specific design problems recurring in certain requirements contexts. Focus-
ing on remote APIs (rather than program-internal ones), they aim at improving the
developer experience on both the client side and the provider side.
Target Audience
This book targets intermediate-level software professionals striving to improve their
skills and designs. The presented patterns primarily aim at integration architects,
API designers, and Web developers interested in platform-independent architectural
knowledge. Both backend-to-backend integration specialists and developers of APIs
supporting frontend applications can benefit from the knowledge captured in the
patterns. As we focus on API endpoint granularity and the data exchanged in mes-
sages, additional target roles are API product owner, API reviewer, and cloud tenant
and provider.
This book is for you if you are a medium-experienced software engineer (such
as developer, architect, or product owner) already familiar with API funda-
mentals and want to improve your API design capabilities, including message
data contract design and API evolution.
Students, lecturers, and software engineering researchers may find the patterns
and their presentation in this book useful as well. We provide an introduction to API
fundamentals and a domain model for API design to make the book and its patterns
understandable without first having to read a book for beginners.
xxvi Preface
Knowing about the available patterns and their pros and cons will improve profi-
ciency regarding API design and evolution. APIs and the services they provide will be
simpler to develop, consume, and evolve when applying patterns from this book
suited for a particular requirements context.
Usage Scenarios
Our objective is to make API design and usage a pleasant experience. To that end,
three main use cases for our book and its patterns are as follows:
1. Facilitate API design discussions and workshops by establishing a common
vocabulary, pointing out required design decisions, and sharing available
options and related trade-offs. Empowered by this knowledge, API providers
are enabled to expose APIs of quality and style that meet their clients’ needs,
both short term and long term.
2. Simplify API design reviews and speed up objective API comparisons so that
APIs can be quality assured—and evolved in a backward-compatible and
extensible way.
3. Enhance API documentation with platform-neutral design information so that
API client developers can grasp the capabilities and constraints of provided
APIs with ease. The patterns are designed to be embeddable into API contracts
and observable in existing designs.
We provide a fictitious case study and two real-world pattern adoption stories to
demonstrate and jumpstart this pattern usage.
We do not expect readers to know any particular modeling approach, design tech-
nique, or architectural style already. However, such concepts—for instance, the
Align-Define-Design-Refine (ADDR) process, domain-driven design (DDD), and
responsibility-driven design (RDD)—have their roles to play. They are reviewed
briefly in Appendix A.
Patterns are not invented but are mined from practical experience and then hard-
ened via peer feedback. The patterns community has developed a set of practices to
organize the feedback process; shepherding and writers’ workshops are two particu-
larly important ones [Coplien 1997].
At the heart of each pattern is a problem-solution pair. Its forces and the discus-
sion of consequences support informed decision making, for instance, about desired
and achieved quality characteristics—but also about the downsides of certain
designs. Alternative solutions are discussed, and pointers to related patterns and
possible implementation technologies complete the picture.
Note that patterns do not aim at providing complete solutions but serve as
sketches to be adopted and tailored for a particular, context-specific API design. In
other words, patterns are soft around their edges; they outline possible solutions but
do not provide blueprints to be copied blindly. How to adopt and realize a pattern to
satisfy project or product requirements remains the responsibility of API designers
and owners.
We have been applying and teaching patterns in industry and academia for a long
time. Some of us have written patterns for programming, architecting, and integrat-
ing distributed application systems and their parts [Voelter 2004; Zimmermann
2009; Pautasso 2016].
We found the pattern concept to be well suited for the usage scenarios stated ear-
lier under “Goals and Scope” and “Target Audience.”
• What is the architectural role played by each API endpoint? How do the end-
point roles and the responsibilities of operations impact service size and
granularity?
• What is an adequate number of representation elements in request and
response messages? How are these elements structured? How can they be
grouped and annotated with supplemental information?
• How can an API provider achieve a certain level of API quality while at the
same time using its resources in a cost-effective way? How can quality trade-
offs be communicated and accounted for?
• How can API professionals deal with life-cycle management concerns such as
support periods and versioning? How can they promote backward compatibil-
ity and communicate unavoidable breaking changes?
1. https://europlop.net/content/conference.
2. We decided not to include big collections of known uses in the book; such information is available
online and in the EuroPLoP conference proceedings from 2016 to 2020. In some of the supplemental
resources, you can find extra implementation hints as well.
xxx Preface
Preface:
Goals and Scope, Target Audience, Patterns, Content Organization, Reading Order
Part 2
Part 1
Chapter 4: Part 3
Pattern Language Introduction
Chapter 1:
API Fundamentals Chapter 10:
Chapters 5 to 9: Real-World
Chapters
Pattern 5 to 9:
Themes Pattern Stories
Chapter 2: Chapters 5 to 9:
Pattern Themes
Lakeside Mutual Chapters
Pattern Themes5 to 9:
Case Study Chapters
Pattern Themes5 to 9:
Pattern Reference Chapter 11:
Conclusion
Chapter 3: API
Decision Narratives
Appendices A to C:
A: Endpoint Identification and Pattern Selection Guides (including Cheat Sheet)
B: Implementation of the Lakeside Mutual Case
C: Microservice Domain-Specific Language (MDSL)
Part 1 introduces the domain of API design conceptually, starting with Chapter 1,
“Application Programming Interface (API) Fundamentals.” Lakeside Mutual, our
case study and primary source of examples, appears for the first time with its business
context, requirements, existing systems, and initial API design in Chapter 2, “Lakeside
Mutual Case Study.” We provide decision models that show how the patterns in our
language relate to each other in Chapter 3, “API Decision Narratives.” Chapter 3 also
provides pattern selection criteria and shows how the featured decisions were made in the
Lakeside Mutual case. These decision models may serve as navigation aids when reading
the book and when applying the patterns in practice.
Preface xxxi
Part 2 is the pattern reference; it starts with Chapter 4, “Pattern Language Intro-
duction,” followed by five chapters full of patterns: Chapter 5, “Define Endpoint
Types and Operations,” Chapter 6, “Design Request and Response Message Rep-
resentations,” Chapter 7, “Refine Message Design for Quality,” Chapter 8,
“Evolve APIs,” and Chapter 9, “Document and Communicate API Contracts.”
Figure P.2 illustrates these chapters and possible reading paths in this part; for instance,
you can learn about basic structure patterns such as Atomic Parameter and Parame-
ter Tree in Chapter 4 and then move on to element stereotypes such as Id Element
and Metadata Element found in Chapter 6.
Define
Responsibility Patterns
(Chapter 5)
Evolution Patterns
Align Refine (Chapter 8)
Endpoint Roles
Foundation Patterns
Quality Patterns
(Chapter 4)
(Chapter 7) Versioning
Operation
Integration Types Responsibilities
(API Direction) Message Granularity Lifecycle
Management
Guarantees
API Visibility
Client-Driven
Design Message Content
Documentation Patterns
Basic Structure Message Structuring (Chapter 9)
Patterns Patterns (Chapter 6) Message Exchange
Optimization
API Description
Element Stereotypes
Billing and
Special-Purpose Governance
Representations
Each pattern description can be seen as a small, specialized article on its own,
usually a few pages long. These discussions are structured identically: First, we intro-
duce when and why to apply the pattern. Then we explain how the pattern works
and give at least one concrete example. Next, we discuss the consequences of apply-
ing the pattern and direct readers to other patterns that become eligible once a par-
ticular one has been applied. The names of our patterns are set in small caps
(example: Processing Resource). This pattern template, introduced in detail in
Chapter 4, was derived from the EuroPLoP conference template [Harrison 2003]. We
refactored it slightly to take review comments and advice into account (thank you
Gregor and Peter!). It puts particular emphasis on quality attributes and their con-
flicts, as our patterns deal with architecturally significant requirements; conse-
quently, trade-offs are required when making API design and evolution decisions.
Part 3 features the application of the patterns in two real-world projects in rather
different domains, e-government and offer/order management in the construction
industry. It also reflects, draws some conclusions, and gives an outlook.
xxxii Preface
Register your copy of Patterns for API Design: Simplifying Integration with Loosely
Coupled Message Exchanges on the InformIT site for convenient access to updates
and/or corrections as they become available. To start the registration process, go to
informit.com/register and log in or create an account. Enter the product ISBN
(9780137670109) and click Submit. Look on the Registered Products tab for an
Access Bonus Content link next to this product, and follow that link to access any
available bonus materials. If you would like to be notified of exclusive offers on new
editions and updates, please check the box to receive email from us.
Acknowledgments
We thank Vaughn Vernon for all his feedback and encouragement during our book pro-
ject. We feel honored to be part of his Addison Wesley Signature Series. Special thanks
also go to Haze Humbert, Menka Mehta, Mary Roth, Karthik Orukaimani, and Sandra
Schroeder from Pearson for their excellent support and to Frank Leymann for providing
the foreword and valuable feedback on our work. Our copy editor, Carol Lallier of Clar-
ity Editing, made this late activity a rewarding, even pleasant experience.
The real-world pattern stories in this book would have not been possible without
the cooperation of development projects. Thus, we’d like to thank Walter Berli and
Werner Möckli from Terravis and Phillip Ghadir and Willem van Kerkhof from innoQ
for their inputs and work on these stories. Nicolas Dipner and Sebnem Kaslack created
the initial versions of the patterns icons in their term and bachelor thesis projects. Toni
Suter implemented large parts of the Lakeside Mutual case study applications. Stefan
Kapferer, developer of Context Mapper, also contributed to the MDSL tools.
We want to thank all the people who provided feedback on the content of this
book. Special thanks go to Andrei Furda, who provided input to the introductory
material and reviewed many of our patterns; Oliver Kopp and Hans-Peter Hoidn,
who applied patterns, provided feedback, and/or organized several informal work-
shops with peers; James Higginbotham and, again, Hans-Peter Hoidn, who reviewed
the book manuscript.
In addition, many colleagues provided helpful feedback, especially the shepherds and
writer’s workshop participants from EuroPLoP 2017, 2018, 2019, and 2020. We thank
the following individuals for their valuable insights: Linus Basig, Luc Bläser, Thomas
Brand, Joseph Corneli, Filipe Correia, Dominic Gabriel, Antonio Gámez Díaz, Reto
Fankhauser, Hugo Sereno Ferreira, Silvan Gehrig, Alex Gfeller, Gregor Hohpe, Stefan
Holtel, Ana Ivanchikj, Stefan Keller, Michael Krisper, Jochen Küster, Fabrizio Lazzaretti,
Giacomo De Liberali, Fabrizio Montesi, Frank Müller, Padmalata Nistala, Philipp Oser,
Ipek Ozkaya, Boris Pokorny, Stefan Richter, Thomas Ronzon, Andreas Sahlbach, Niels
Seidel, Souhaila Serbout, Apitchaka Singjai, Stefan Sobernig, Peter Sommerlad, Markus
Stolze, Davide Taibi, Dominic Ullmann, Martin (Uto869), Uwe van Heesch, Timo Ver-
hoeven, Stijn Vermeeren, Tammo van Lessen, Robert Weiser, Erik Wilde, Erik Wittern,
Eoin Woods, Rebecca Wirfs-Brock, and Veith Zäch. We also would like to thank the stu-
dents of several editions of the HSR/OST lectures “Advanced Patterns and Frameworks”
and “Application Architecture” and of the USI lecture on “Software Architecture.” Their
discussion of our patterns and additional feedback are appreciated.
xxxiii
This page intentionally left blank
About the Authors
Mirko Stocker is a programmer by heart who could not decide whether he liked
frontend or backend development more, so he stayed in the middle and discovered
that APIs hold many interesting challenges as well. He cofounded two startups in the
legal tech sector, one of which he still chairs as managing director. This path has led
him to become a professor of software engineering at the Eastern Switzerland Uni-
versity of Applied Sciences, where he researches and teaches in the areas of program-
ming languages, software architecture, and Web engineering.
xxxv
xxxvi About the Authors
Cesare Pautasso is a full professor at the Software Institute of the USI Faculty of
Informatics, in Lugano, Switzerland, where he leads the Architecture, Design, and
Web Information Systems Engineering research group. He chaired the 25th European
Conference on Pattern Languages of Programs (EuroPLoP 2022). He was lucky to
meet Olaf during a brief stint at the IBM Zurich Research Lab back in 2007, after
receiving his PhD from ETH Zurich in 2004. He has co-authored SOA with REST
(Prentice Hall, 2013) and, self-published the Beautiful APIs series, RESTful Diction-
ary, and Just Send an Email: Anti-patterns for Email-centric Organizations on
LeanPub.
Part 1
The three chapters in Part 1 prepare you to make the best use of Patterns for API
Design. Chapter 1, “Application Programming Interface (API) Fundamentals,” intro-
duces basic API concepts and motivates why remote APIs are important and rather
hard to design well. This chapter sets the stage for the following ones.
Chapter 2, “Lakeside Mutual Case Study,” introduces a fictitious case study from
the insurance domain that supplies running examples for the book. The systems of
Lakeside Mutual feature our patterns in action.
Chapter 3, “API Decision Narratives,” gives an overview of the patterns in the
form of decisions required. (The patterns are then covered in depth in Part 2.) Each
decision answers an API design question; the patterns provide the solution alterna-
tives (options). Examples of decision outcomes from the Lakeside Mutual case are
given as well. The decision model presented in this chapter can help you organize
your API design work and/or serve as a checklist in API design reviews.
1
This page intentionally left blank
Chapter 1
Application Programming
Interface (API) Fundamentals
This chapter first establishes the context of remote APIs. Next, it motivates why APIs
are so important today. It also calls out the main design challenges for APIs, includ-
ing coupling and granularity concerns. Finally, it introduces an API domain model to
establish the terminology and concepts used throughout the book.
3
4 Chapter 1 Application Programming Interface (API) Fundamentals
API contracts express the expectations of the interacting parties. Following basic
information-hiding principles, the implementation is kept secret. Only a minimum
amount of information on how to contact the API and how to consume its services
is revealed. For example, the developer of a software engineering tool that integrates
with GitHub is informed how to create and retrieve issues and which attributes (or
fields) an issue contains. The GitHub API does not unveil the programming lan-
guage, database technology, component structure, or database schema within the
issue management application that serves the public API.
It is worth noting that not all systems and services feature APIs from the start;
APIs may also disappear over time. For example, Twitter opened its Web API to
third-party client developers to increase its popularity; soon, an entire client eco-
system emerged that attracted many users. To monetize its user-generated content,
Twitter later closed down the API and acquired some client applications to continue
maintaining them in-house. We can conclude that API evolution over time has to be
managed.
• The transport and networking protocols TCP/IP along with their socket API,
the backbone of the Internet, were developed in the 1970s. The same holds for
file transfer protocols such as FTP and basic file input/output (from/to shared
drives or mounted network file systems), arguably available in all program-
ming languages past and present.
• Remote Procedure Calls (RPCs), such as the distributed computing envi-
ronment (DCE), and object-oriented request brokers, such as CORBA and
Java RMI, added abstraction and convenience layers in the 1980s and 1990s.
Recently, newer variants of RPC, such as gRPC, became popular.
• Queue-based, message-oriented application integration, such as IBM
MQSeries and Apache ActiveMQ, help to decouple communication parties in
the time dimension. They are about as old as RPCs, with new implementations
6 Chapter 1 Application Programming Interface (API) Fundamentals
and flavors emerging since the 2000s. For instance, major cloud providers offer
their own messaging services today. Cloud tenants can also deploy other mes-
saging middleware to cloud infrastructures; RabbitMQ is a frequent choice in
practice.
• Due to the popularity of the World Wide Web, hypermedia-oriented proto-
cols such as HTTP have risen in the last two decades. To qualify as RESTful
would require respecting all architectural constraints of the Representational
State Transfer (REST) style. While not all HTTP APIs do so, HTTP seems to
dominate the public application integration space at present.
• Data processing pipelines built over continuous data streams, such as those
built with Apache Kafka, have their roots in classical UNIX pipes-and-filters
architectures. They are particularly popular in data analytics scenarios (for
example, analysis of Web traffic and online shopping behavior).
Application A Application B
API Client API Endpoint Provider
Remote API
SDK Message
Representation
Middleware
Local API OS Local API
Platform A Platform B
Network Protocols
(often TCP/IP)
Figure 1.1 Message-based integration and concepts in remote APIs (OS: operating system,
SDK: software development kit)
Remote APIs provide a virtual, abstract connection between the integrated appli-
cation parts. Each remote API is realized by at least three other APIs: a local one both
on the client side and on the provider side plus a remote interface on the next lower
layer of the communication stack. The two local interfaces are provided by operating
system, middleware, or programming language libraries and software development
kits (SDKs); they are consumed by the applications on both the API client and the
API provider sides. These local interfaces expose the networking/transport proto-
col services, such as HTTP over TCP/IP sockets, to application components, subsys-
tems, or entire applications requiring integration.
To reach the common goal of interoperable communication, a shared under-
standing between the communication participants has to be established in an API
contract. When defining API contracts, protocols and endpoints supporting them
are one side of the coin; the exposed data is the other. Request and response mes-
sage representations have to be structured somehow.1 Even file import/exports or
transfers require careful message design; the files contain these messages in that case.
Clipboard-based integration has similar properties. The API contract describes the
1. It depends on the message exchange pattern in use whether a response message is present (our API
domain model, introduced later in this chapter, covers this topic).
8 Chapter 1 Application Programming Interface (API) Fundamentals
shared knowledge about message syntax, structure, and semantics that connects—
but also separates—the two parties.
Our definition of remote API follows from these thoughts:
A remote API is a set of well-documented network endpoints that allow internal and
external application components to provide services to each other. These services help
achieve domain-specific goals, for instance, fully or partially automating business pro-
cesses. They allow clients to activate provider-side processing logic or support data
exchanges and event notifications.
This definition establishes the design space of our book. Note that our book is
on remote APIs; hence, the term API refers to remote APIs from now on—unless we
explicitly say that we mean a local API.
Designing APIs is highly challenging. Many decision drivers, also called forces or
quality attributes, play vital roles in their design. “Decision Drivers in API Design,”
later in this chapter, discusses these desired qualities.
APIs Matter
Let us now visit some business domains and technology areas in which we find many
APIs today.
• Create and manage ad campaigns. Obtain the status of keywords and ads.
Generate keyword estimates. Generate reports about campaign performance.
• Open bank accounts with customer identity verification.
• Manage and deploy applications on virtual machines and track resource
consumption.
• Identify a single person. Find their phone numbers, email addresses, locations,
and demographics.
• Collect, discover, and share your favorite quotes.
From Local Interfaces to Remote APIs 9
In all these examples, API contracts define where and how to call the API, which
data to send, and how received responses look. Some of these domains and services
actually depend on APIs and would not exist without them. Let us now investigate
some of these domains and services in more depth.
10 Chapter 1 Application Programming Interface (API) Fundamentals
Application Application
Frontend Backend
Queue
Tenant Ops Mobile App
APIs Cloud
Database
Business Logic
API
Other Cloud
Storage
Cloud
Compute
API Services
External Services
(Other Cloud, On Premise)
Trait 2, rightsized and modular, directly calls for the introduction of APIs.
Cloud application management (trait 5) also requires APIs, and DevOps tool chains
(trait 7) benefit from them, too.
The cluster management software Kubernetes, for example, has become a pop-
ular choice for running applications and orchestrating the underlying computing
resources both on premises and in the cloud. It addresses the problem of having
to deploy many individual applications and services repeatedly. All these applica-
tion services communicate with each other and with their clients through APIs. The
Kubernetes platform itself also exposes management APIs [Kubernetes 2022] as
well as command-line interfaces. Its operator concept, exposed via API and an SDK
12 Chapter 1 Application Programming Interface (API) Fundamentals
on top of it, promotes extensibility. Application APIs can even be managed with
Kubernetes.
As another example, software-as-a-service providers typically not only provide
customizable, multitenant end-user applications but also open up their applica-
tion functionality to third parties via HTTP. An example is Salesforce, offering data
access and integration in HTTP APIs. At the time of writing, 28 APIs were avail-
able, covering rather diverse domains such as marketing, business-to-consumer com-
merce, and customer data management.
Data consistency and state management challenges are introduced, for example,
when decoupling monolithic, stateful applications into independent, autonomous
microservices [Furda 2018]; single points of failure or cascading failure proliferation
effects have to be avoided. Autonomy and consistency for the whole microservice
architecture cannot be guaranteed at the same time when employing a traditional
backup and disaster recovery strategy [Pardon 2018]. Scaling the architecture to
include a large number of microservices requires a disciplined approach to their life
cycle management, monitoring, and debugging.
Some of these challenges can be overcome with adequate infrastructures. For
example, load balancers introduce (managed) redundancy and circuit breakers
[Nygard 2018a] reduce the risk that failing downstream microservice instances bring
down upstream ones (and, eventually, the entire system). The service APIs still have
to be rightsized and evolved properly over time.
In this book, we are not concerned with microservices infrastructures but with
service rightsizing on the API level (in terms of endpoint granularity and operation/
data coupling). However, infrastructure design is eased when API services have ade-
quate sizes; so indirectly, we are also concerned about infrastructure design.
Wrap Up
All examples, scenarios, and domains we have visited in this section contain and
depend on remote APIs and their contracts, and there are more. If you are up for a
round of buzzword bingo: APIs are an enabling technology for most (if not all) major
trends in recent years—not only mobile/Web and cloud, as mentioned earlier, but
also artificial intelligence and machine learning, the Internet of Things, smart cities,
and smart grids. Even quantum computing in the cloud relies on APIs; see, for exam-
ple, the Quantum Engine API provided by Google Quantum AI.4
4. Bingo!
Decision Drivers in API Design 15
If the API is used in a commercial setting, the success of an API can be assessed
according to business value focusing on the economic sustainability of the service
operating costs versus the revenues generated directly or indirectly from each API
client. Different business models are possible, ranging from freely accessible APIs,
funded by advertisers interested in mining the data willingly (or not willingly?) pro-
vided by users of the applications built on top of the API, to subscription-based APIs
and pay-per-use APIs offered under different pricing plans. For example, Google
Maps used to be a standalone Web application. The Google Maps API appeared
only after users started to reverse engineer how to embed map visualizations in
their own Web sites. Here, an initially closed architecture opened up following user
demand. The initially freely accessible API was later turned into a lucrative pay-per-
use service. OpenStreetMap, the open-source alternative to Google Maps, also pro-
vides several APIs.
A second success factor is visibility. The best API design will fail if its prospective
clients do not know it exists. Public APIs, for instance, may be discovered via links
to provided APIs in company products and product documentation or by advertis-
ing their existence within developer communities. Moreover, API directories such as
ProgrammableWeb and APIs.guru exist. Either way, investments for making the API
known should pay off eventually.
Time to market for APIs can be measured in terms of how long it takes to deploy
new features or bug fixes to an API as well as in terms of how long it takes to
develop a fully functional client for the API. The time to first call is a good indicator
of the quality of the API documentation and the onboarding experience of client
16 Chapter 1 Application Programming Interface (API) Fundamentals
developers. To keep this measure low, the learning effort should be low, too. Another
metric might be the time to first level n ticket—hopefully, it takes a long time for an
API client developer to find a bug that requires level 1, 2, or 3 support to resolve.
Another success measure is the API lifetime. APIs may outlive their original
designers. A successful API usually survives because it keeps attracting clients by
adapting to their changing needs over time. However, a stable API that does not
change for a long time can still be in active use by clients—including those not having
an alternative, such as when fulfilling regulatory compliance requirements via stand-
ardized, slow-moving e-government APIs.
In summary, APIs enable rapid integration of systems and their parts in the short
term and have to support the autonomy and independent evolution of these systems
in the long term. The goal of rapid integration is to decrease the cost of bringing
two systems together; independent evolution has to prevent systems from becoming
so entangled and coupled that they can no longer be separated (or replaced). These
objectives conflict with each other to some extent—which will keep us busy through-
out the book.
These questions, options, and criteria challenge API designers; different choices
are made in different requirements contexts. Our patterns discuss possible answers
and their consequences.
• Client diversity: The wants and needs of API clients differ from one client to
another, and they keep changing. API providers have to decide whether they
want to offer good-enough compromises in a single, unified API or try to sat-
isfy specific, diverging client requirements individually.
• Market dynamics: Competing API providers trying to catch up on each other’s
innovations may cause more change and possibly incompatible evolution strat-
egies than clients are able or willing to accept. Furthermore, clients look for
standardized APIs as a means of preserving their independence from specific
providers, while some providers may be tempted to lock clients in by offering
enticing extensions. Wouldn’t it be nice if Google Maps and OpenStreetMap
APIs implemented the same set of APIs? Client and provider developers might
answer this question differently.
18 Chapter 1 Application Programming Interface (API) Fundamentals
5. How many XML developers and tools are still out there?
Decision Drivers in API Design 19
In summary, API design can make or break software projects, products, and eco-
systems. An API is not just a mere implementation artifact but an integration asset;
APIs have to be architected well due to their dual connector-separator role and typi-
cally long lifetime. While technologies come and go, many of the underlying design
problems for integration designers and solutions to them stay the same.
Related architecturally significant requirements, covered next, change somewhat,
but a common set has stayed relevant for a long time.
6. Think of business processes and corresponding forms to be filled out and approvals required in large
enterprises: typically, many activities and data fields are added with good intentions, but these addi-
tions hardly ever replace existing ones.
Decision Drivers in API Design 21
Developer Experience
The DX metaphor and analogy to user experience (UX) has become quite popular in
recent years. According to Albert Cavalcante’s blog post “What Is DX?” [Cavalcante
2019], the four pillars of a pleasant DX, combining input from UX with software
design principles, are
7. We might be able to train them in some constrained domains such as image recognition, but we cannot
expect them to build a value system and behave morally/ethically as humans (hopefully) do.
22 Chapter 1 Application Programming Interface (API) Fundamentals
While DX receives a lot of attention (rightfully) and can be seen to include main-
tainer experience and consultant/educator/learner experience, do we hear and know
enough about the operator experience?
In conclusion, API success indeed has at least two facets, short-term positivity
and long-term use:
First impressions last. The easier and clearer it is to successfully place the first call to
an API, and to do something meaningful with the responses, the more client developers
will use the API—and enjoy the experience (with regards to function, stability, ease of
use, and clarity). Runtime qualities such as performance, reliability, and manageability
decide whether a positive initial developer experience causes API usage to sustain.
The next and final section in this chapter introduces the API domain model that
serves as our book vocabulary and glossary.
Communication Participants
At an abstract level, two kinds of communication participants (participants, for
short) communicate via an API, the API provider, and the API client. An API client
may use (or consume) any number of API endpoints. The communication is gov-
erned by the API contract, which is exposed by the API provider and consumed by its
clients. This API contract contains information about the available endpoints that
offer the functionality specified by the contract. Figure 1.3 visualizes these basic con-
cepts and relations.
A Domain Model for Remote APIs 23
Communication
uses
Participant
* 1
consumes exposes
* *
API Contract lists API Endpoint Address
1 1..* has
offers 1 1
1 1..*
Figure 1.3 Domain model for API design and evolution: Communication participants, API
contract, API endpoint
Note that the API as a whole is not shown in the figure; an API is a collection of
endpoints with the contracts offered by them. An API endpoint represents the pro-
vider-side end of a communication channel; an API contains at least one such end-
point. Each API endpoint has a unique address such as a Uniform Resource Locator
(URL), commonly used on the World Wide Web, RESTful HTTP, and HTTP-based
SOAP. In the client role, a communication participant accesses an API via such an
endpoint. A communication participant may play both the client role and the pro-
vider role. In that case, a communication participant offers certain services as an API
provider but also consumes services offered by other APIs in its implementation.8
In service-oriented architecture terminology, the term service consumer is a
synonym for API client; the API provider is called service provider [Zimmermann
2009]. In HTTP, an API endpoint corresponds to a set of related resources. A home
resource with a prepublished URI is an entry-level URL to locate and access one or
more related resources.
8. The client-side of a communication channel also requires a network endpoint, which is not depicted
here due to our focus on APIs rather than communication channels or networking.
24 Chapter 1 Application Programming Interface (API) Fundamentals
9. In OpenAPI specifications, operations are identified by the HTTP method and its URI path; there also
is an additional property, operationId [OpenAPI 2022].
A Domain Model for Remote APIs 25
Request/Reply
Command
Message
One-Way composed of
Exchange
*
Conversation Message Document
comprises Message
- header
* * - body
Event
Notification
Event Message
From Enterprise
Request-
Integration Patterns
Multiple Replies
(Callbacks)
Many other kinds of conversations exist, including more complex ones like
publish-subscribe mechanisms. Basic conversations can be composed into larger
end-to-end conversations scenarios involving message exchanges between multi-
ple API clients and providers up to managed business processes that run for days,
months, or years. [Pautasso 2016; Hohpe 2017]. Such advanced conversations can
commonly be found in software ecosystems, enterprise applications, and other API
usage scenarios, but they are not our main focus in this book.
contains from
Message address Address API Endpoint
1 0..1 has
- header
- body 1 1
1 contains to
address 0..1
1
has
1..*
Representation Representation
assembles Element
+ serialize() (Parameter)
+ deserialize() * *
API Contract
Figure 1.7 shows that all endpoint operations are specified in the API contract (which we
introduced in Figure 1.3). Such a contract may detail all possible conversations and mes-
sages down to the protocol-level message representations (parameters, bodies) and
network addresses. API contracts are necessary to realize any interoperable, testable, and
evolvable runtime communication because API clients and API providers must agree on
the shared knowledge specified in the contract in order to be able to communicate.
10. A DTR can be seen as a wire-level equivalent of a program-level pattern data transfer object (DTO)
[Fowler 2002; Daigneau 2011].
A Domain Model for Remote APIs 27
In reality, this agreement can be highly asymmetrical because many APIs (espe-
cially public APIs) are offered as-is by the API provider. API clients can use it under
those conditions or not at all; no negotiation or formal agreement on a contract
between the participants takes place in such cases. This might be different if the API
client pays for the service. In that case, the API contract might be the result of an
actual negotiation and be accompanied by (or even part of) a legal contract. An API
contract can either be documented minimally or be part of a more comprehensive
API Description and/or Service Level Agreement (two of our patterns).
Communication
Participant uses
agrees
on
*
API Contract
1 1
describes offers
* 1..*
+ ID: String
Figure 1.7 Domain model: An API contract describes operations (that are invoked in
conversations comprising messages)
driver for a decision for or against a pattern. For instance, the parameter structure of
each occurrence of a message has to be decided. Chapter 3, “API Decision Narra-
tives,” picks up these thoughts and guides us through the decision making about all
domain model elements and patterns.
Finally, the Microservices Domain-Specific Language (MDSL) that we use to
model some examples is designed according to this domain model. See Appendix C,
“Microservice Domain-Specific Language (MDSL),” for reference information.
Summary
In this chapter, we discussed the following:
• What APIs are and why they are important—and challenging—to design well.
• Desired qualities in API design, including coupling and granularity considera-
tions and elements of a positive developer experience (DX).
• The API domain terminology and concepts we use in this book.
APIs, both local APIs inside modular programs and remote APIs connecting oper-
ating system processes and distributed systems, have been around for a long time.
Message-based protocols such as RESTful HTTP, gRPC, and GraphQL dominate
the remote API realm at present. Remote APIs provide the means to access server-side
resources via protocols for application integration. They play the role of an impor-
tant intermediary, which connects multiple systems while keeping them as separate
as possible to minimize the impact of future changes. An API and its implementa-
tions may even remain under separate control and ownership. Any API, whether
local or remote, should address an actual client information or integration need and
be purposeful.
A real-world metaphor would be to see the API as an entrance door and hall of
a building, for instance, the lobby welcoming visitors to a skyscraper, routing them
to the right elevator but also checking whether they are allowed to enter through the
main door. First impressions last when entering a place for the first time—in real
life between humans, when humans use software, or when API clients use APIs. An
API portal, then, serves as a set of “business cards” (or building map) of the applica-
tion behind the API, introducing services to developers potentially interested in using
them to build their own applications. Both business cards and entrance hall influence
the visitor experience (in this case, DX).
Getting local APIs right is one thing. For remote APIs, the fallacies of distributed
computing come into play. Networks cannot be assumed to be reliable, for example,
Summary 29
Why is it hard (and interesting) to get API design and evolution right?
• APIs are supposed to live long; API success has a short-term and a long-term
perspective.
• APIs require different and diverse parties to reach agreements regarding
exposed functionality and related qualities.
• The granularity of APIs is determined by the number of endpoints and oper-
ations exposed as well as by the data contracts of the request and response
messages of these operations. An important decision point concerns choosing
between a few rich operations and many narrow ones.
• Coupling control is required. Zero coupling means being disconnected; the
more API client and API provider (have to) know about each other, the tighter
they are coupled, and the harder it becomes to evolve them independently.
• While API technologies come and go, the fundamental concepts of API design
and the related architectural decisions with their options and criteria stay.
30 Chapter 1 Application Programming Interface (API) Fundamentals
Our focus in this book is on remote APIs connecting systems and their parts. API
providers expose API endpoints, which have operations; operations are called via
message exchanges. The messages in these exchanges form conversations; they con-
tain flat or structured message representation elements. We defined these concepts in
a domain model for API design and evolution. Bringing these concepts to life so that
the resulting APIs meet the wants and needs of their clients with certain qualities is
our task at hand.
What’s up next? Chapter 2, “Lakeside Mutual Case Study,” introduces a larger,
fictitious yet realistic example of an API and service design. Chapter 3 picks up the
design challenges and requirements from this section in the form of decision drivers.
The forces and their resolution in the patterns in Part 2, the pattern reference, also
elaborate on these success factors and quality properties.
Chapter 2
This chapter introduces the Lakeside Mutual case study that serves as our example
scenario running through the book. To motivate the need for APIs in this scenario
and to be able to justify API design decisions in later chapters, sample systems and
the requirements they face are presented, along with an initial API design serving as
an outline and preview.
Lakeside Mutual is a fictitious insurance company that provides several digital
services to its customers, partners, and employees. Its company backend consists of
several enterprise applications for customer, policy, and risk management; the appli-
cation frontends serve multiple channels from smartphone apps for prospective and
insured clients to rich client applications for company staff members and third-party
sales agents.
31
32 Chapter 2 Lakeside Mutual Case Study
Let us inspect these artifacts now. They provide valuable input to the API design.
schedule a home visit. The enterprise applications use domain-driven design (DDD)
[Evans 2003; Vernon 2013] to structure their domain (business) logic. Figure 2.1
shows the three main aggregates Customer, InsuranceQuoteRequest, and Policy.1
«Aggregate»
InsuranceQuoteRequest
«Aggregate» «Aggregate»
Policy Customer
insures
We now zoom into these three aggregates to explore additional DDD concepts.
Insurance quote requests come from existing or prospective customers. They inquire
about offers for new insurance policies (such as health care or car insurance). Offers
and policies know about the customers who (will) pay for them and who may issue
claims in the future.
Figure 2.2 shows the components of the InsuranceQuoteRequest aggregate, which
is an example of short-lived operational data. It comprises several entities with an
identity and life cycle and immutable value objects. An entity with a unique role is the
InsuranceQuoteRequest aggregate root. It serves as an entry point into the aggregate
and holds the components of the aggregate together. We can also see some outgoing
references to other aggregates, pointing at the respective aggregate root entities. For
example, an InsuranceQuoteRequest references a customer’s existing policies that
the customer now wishes to change. The request also includes CustomerInfo, which
refers to one or more addresses, because a policy might pertain to several persons
(and persons might have multiple residences too). For example, health insurance for
children can be part of a parent’s policy.
1. Aggregates are clusters of domain objects loaded and stored together, enforcing the related business
rules.
34 Chapter 2 Lakeside Mutual Case Study
«Aggregate»
InsuranceQuoteRequest
- id: long
- date: Date
customer
insuranceQuote
«Aggregate»
Customer
«entity» «entity»
InsuranceQuote CustomerInfo
Details of the Policy aggregate are shown in Figure 2.3. A policy deals primarily
with value objects such as MoneyAmounts, types of policies, and date periods. Each
policy also has an identifier (PolicyId) used to reference the aggregate from the out-
side. On the right, we can see the reference to the Customer aggregate.
«Aggregate»
Policy
- creationDate: Date
deductible policyLimit
policyType insurancePremium policyPeriod insuringAgreement
agreementItems
«Value Object»
InsuringAgreementItem
In Figure 2.4, we finally arrive at the Customer aggregate that holds the usual
contact information and current and past addresses. Like policies, customers can be
identified uniquely by their CustomerId.
customer customer
«Aggregate»
Customer
«Aggregate Root»
Customer
id customerProfile
- streetAddress: String
- postalCode: String
moveHistory - city: String
Architecture Overview
Now that we know about business context and requirements, let us investigate the
existing systems at Lakeside Mutual and their architectures.
System Context
Figure 2.5 shows the current system context. Existing customers (not shown in the
figure) should be able to use the Customer Self-Service frontend to update their con-
tact information. This service retrieves the master data from the Customer Core
36 Chapter 2 Lakeside Mutual Case Study
Customer Core
U OHS
U
U
Customer/Supplier
D CF
D
U U
Customer/Supplier
Customer/Supplier
D D
D
Customer Self-Service
Figure 2.5 Context map for Lakeside Mutual (solid lines: existing relations, dashed line:
new interface)
The four applications shown as Bounded Contexts in the figure are easy to trace
back to the analysis-level domain model.3 The Customer Self-Service context cur-
rently interacts only with Policy Management and Customer Core. To implement
the new self-service capabilities, a new relationship to the Customer Management
context will be added, which the dashed line in Figure 2.5 indicates. In the next sec-
tion, we look at the software architecture that implements these bounded contexts.
Application Architecture
Refining the system context from Figure 2.5, Figure 2.6 shows an overview of the
core components. These components are the building blocks for the services Lake-
side Mutual provides to its customers and its employees. The Bounded Contexts
from Figure 2.5 have led to the introduction of respective frontend applications and
2. Note that Customer/Supplier, Upstream (U), Downstream (D), Open Host Service (OHS), and Conform-
ist (CF) are context relationships from DDD that call for API design and development [Vernon 2013].
3. The DDD pattern Bounded Context denotes a model boundary; it is an abstraction and generalization
of teams, systems, and system parts (such as application frontends and backends).
Architecture Overview 37
«Spring Boot»
Customer Core
The frontend strategy is to use rich Web clients; hence, single-page applications
(SPAs) are implemented in JavaScript. Due to a strategic decision made on the com-
pany level several years ago, most backends are realized in Java, leveraging Spring
Boot dependency injection containers to promote flexibility and maintainability. As
a widespread and mature open-source messaging system, Apache ActiveMQ is used
to integrate customer self-service and policy management.
38 Chapter 2 Lakeside Mutual Case Study
• Customer Core: The Customer Core manages the personal data about the
individual customers (for instance, name, email, current address, etc.). It pro-
vides this data to the other components through an HTTP resource API.
• Customer Self-Service Backend: The Customer Self-Service backend provides
an HTTP resource API for the Customer Self-Service frontend. In addition, it
connects to an ActiveMQ broker provided by the Policy Management backend
to process insurance quote requests.
• Customer Self-Service Frontend: The Customer Self-Service frontend is a React
application that allows users to register themselves, view their current insurance
policy, and in the future, change their address (our exemplary user story).
• Customer Management Backend: The Customer Management backend is a
Spring Boot application that exposes an HTTP resource API for the Customer
Management frontend and the Customer Self-Service frontend. In addition,
Web Sockets are used to implement the chat feature to deliver chat messages in
real time between the call center agent using the Customer Management front-
end and the customer logged into the Customer Self-Service Frontend.
• Customer Management Frontend: The Customer Management frontend is a
React application that allows customer-service operators to interact with cus-
tomers and help them resolve issues related to Lakeside Mutual’s insurance
products.
• Policy Management Backend: The Policy Management backend is a Spring
Boot application that provides an HTTP resource API for the Customer Self-
Service frontend and the Policy Management frontend.
• Policy Management Frontend: The Policy Management frontend is a Java
Script application built with vue.js that allows Lakeside Mutual employees to
view and manage the insurance policies of individual customers.
How can patterns help the API designers at Lakeside Mutual when dealing with
these tasks? This question will be answered in the following (and the remainder of
the book). Appendix B, “Implementation of the Lakeside Mutual Case,” collects
some of the API implementation artifacts for the case.
"postalCode": D<string>,
"city": D<string>
}
4. Originally, YAML stood for “Yet Another Markup Language.” However, the name was later changed
to “YAML Ain’t Markup Language” to distinguish it as a data serialization language, not a true
markup language.
Summary 41
At the top level, we can see the API description, two data type definitions, and an
endpoint featuring a single operation. The <<API_Key>> stereotype, SOLUTION_
INTERNAL_API, FRONTEND_INTEGRATION, INFORMATION_HOLDER_RESOURCE,
and STATE_TRANSITION_OPERATION markers (and several others) all refer to pat-
terns. In the next part of the book, these are explained in detail.
Summary
In this chapter, we introduced Lakeside Mutual, a fictitious case study that supplies
us with running examples throughout the remainder of the book. Lakeside Mutual is
an insurance company that implemented its core business capabilities for customer,
contract, and risk management as a set of microservices with corresponding applica-
tion frontends:
We elaborate on this initial API design in Chapter 3 and in Part 2 of the book,
revisiting the patterns and the rationale for their application in the business and
architectural context of the API design of the customer self-service API.
Some excerpts of the API implementation can be found in Appendix B. A com-
plete implementation of the scenario is available at GitHub.5
5. https://github.com/Microservice-API-Patterns/LakesideMutual.
This page intentionally left blank
Chapter 3
API endpoint, operation, and message design is multifaceted and therefore not easy.
Requirements often conflict with each other, requiring balancing acts. Many archi-
tectural decisions and implementation choices have to be made, with numerous solu-
tion options available. The key to the success of an API is getting these decisions
right. Sometimes the required choices are not known to developers, or developers
know only a subset of the available options. Also, not all criteria may be obvious; for
example, some quality attributes (such as performance and security) are more obvi-
ous than others (such as sustainability).
In this chapter, we identify pattern selection decisions by topical categories. The
chapter walks through an API design iteration, starting with API scoping and then
moving on to architectural decisions about endpoint roles and operations respon-
sibilities. Decisions about quality-related design refinements and API evolution are
covered as well. We call out the decisions required along with the most prevalent
options (as covered by patterns from Part 2) and criteria for pattern selection that we
have seen in practice.
43
44 Chapter 3 API Decision Narratives
alternatives. These alternative options are provided by our patterns, which are cov-
ered in depth in Part 2 of the book.
To identify decisions required, we use the following format:
Sample decision outcome. We also present examples of decisions from the Lake-
side Mutual case introduced in Chapter 2, “Lakeside Mutual Case Study.” We use
the following architectural decision record (ADR) format:
In the context of [feature or component],
wanting to/facing the need for [requirement or quality goal],
we decided to [option chosen]
and neglected [alternatives]
to achieve [benefit],
accepting that [negative consequences].
1. See https://ozimmer.ch/practices/2020/04/27/ArchitectureDecisionMaking.html.
Foundational API Decisions and Patterns 45
Each why-statement is set in italics so that it is clearly distinguished from the con-
ceptual content of this chapter (the decision points, options, and criteria, that is).
The “neglected” part of the why-statement is optional, and not used in this example.
In the remainder of the chapter, we cover the following decision topics:
• “Foundational API Decisions and Patterns” features API visibility, API integra-
tion types, and documentation of the API.
• “Decisions about API Roles and Responsibilities” discusses the architectural
role of an endpoint, refining information holder roles, and defining operation
responsibilities.
• “Selecting Message Representation Patterns” covers the choice between flat
and nested structures of representation elements and introduces element
stereotypes.
• “Governing API Quality” is multifaceted: identification and authentication of
the API client, metering and charging for API consumption, preventing API cli-
ents from excessive API usage, explicit specification of quality objectives and
penalties, communication of errors, and external context representation.
• “Deciding for API Quality Improvements” deals with pagination, other
means of avoiding unnecessary data transfer, and handling referenced data in
messages.
• “Decisions about API Evolution” has two parts: versioning and compatibility
management and strategies for commissioning and decommissioning.
• Where should the API be accessible from, or how visible is the API?
• Which integration types should be supported by the API?
• Should the API be documented? If so, how should it be documented?
«Category»
Foundations
«Decision»
API Visibility
«Optional Next» «Optional Next»
document visible combine integration type
aspects of the API with selected visibility
contract option
The first decision in this category is on API visibility. In different kinds of APIs,
the API clients that are supposed to use the API might be vastly different, ranging
from a large number of API clients residing in different organizations and locations
to a few well-known API clients within a single organization and/or the same soft-
ware system.
In addition, it has to be decided how the organization of a system in physical tiers
is related to APIs, leading to different possible integration types. A frontend that is
responsible for displaying and controlling an end user interface might be physically
separated from its backends that are in charge of data processing and storage. Such
backends might be split and distributed into several systems and/or subsystems, for
instance, in service-oriented architectures. In both cases, frontend and backend, API-
based integration is possible.
Finally, decisions about API documentation are required. When a service pro-
vider has decided to expose one or more API endpoints, clients must be able to find
out where and how API operations can be called. This includes technical API access
information, such as API endpoint locations or parameters in message representa-
tions, as well as documentation of operation behavior, including pre- and postcondi-
tions, and related quality-of-service guarantees.
API Visibility
You may want to provide a part of an application with a remote API exposing one or
more API endpoints. In such a scenario, an early decision on each API pertains to its
visibility. From a technical viewpoint, this visibility of an API is determined by the
deployment location and its network connections (for instance, the Internet, an
extranet, a company-internal network, or even a single data center). From an organi-
zational viewpoint, the end users served by the API clients influence the required level
of visibility.
This decision is not primarily technical but a managerial or organizational one.
It is often related to budgets and funding considerations. Sometimes the API devel-
opment, operations, and maintenance are funded by a single project or product; in
other cases, several organizations (or units within one) contribute to the API funding.
The decision has important impacts on many technical aspects, however. Com-
pare, for instance, an open, public API exposed on the Internet used by an arbitrary
number of partially unknown API clients to a solution-internal API used by a small
and stable number of other systems and/or subsystems of an organization. The pos-
sible workload that the open, public API has to tolerate might be rather high and
contain numerous peaks; the workload of a solution-internal API with a few well-
known API clients often is significantly lower. As a consequence, the performance
and scalability requirements for the two kinds of API visibility can be very different.
48 Chapter 3 API Decision Narratives
Figure 3.2 illustrates the three decision options for this decision, described as
patterns.
«Decision»
API Visibility
Specifically for Public APIs, it is important to consider the target audience size,
location, and diversity. The wants and needs of the target audience, possible devel-
opment and middleware platforms they use, and other such considerations can help
determine whether and how an API should be publicly offered. For example, the
trend toward single-page applications that access APIs through the browser (in con-
trast to dynamic Web sites rendered on the server) has led to an increase in APIs that
are accessible over the Internet.
Public APIs with high visibility often have to cope with continuously high work-
loads and/or peak loads. This can increase the complexity and require high maturity
of backend systems and data stores. Possible loads the API has to take are dependent
on the target audience size. The location of the target audience determines the level
of Internet access and bandwidth required.
More visible APIs might have higher security demands than less visible ones. The
use of API Keys or, alternatively, authentication protocols usually indicates the dif-
ference between a Public API in general and its Open API variant: a truly open API
is a Public API without an API Key or other authentication means. Both API Keys
and authentication protocols can also be used in all other options of this decision,
of course.
The costs of API development, operations, and maintenance have to be covered.
Usually, an API must have a business model for generating funds. For Public APIs,
paid subscriptions and per-call payments (see Pricing Plan pattern) are common
options. Another option is cross-funding, for instance, via advertising. Such consid-
erations must go along with budget considerations. While it might be easy to fund
the initial development of the first version of an API, its operations, maintenance,
and evolution might be harder to fund in the long run, especially for a successful
Public API with a large number of clients.
An alternative decision option with more limited visibility is Community API.
As for a Public API, the API development, operations, and maintenance of Com-
munity APIs must be funded. Thus, budgets play an equally important role, but
here the specifics of the community and solutions they require determine how they
are covered. In a community of product users, for example, license fees might cover
the budget. A government or nonprofit organization might fund APIs for specific,
restricted user groups to achieve certain community-specific goals. An essential dif-
ference to Solution-Internal APIs (explained shortly) is that it is often not a single
project or product budget that pays for the API. The interests of those who pay for
the API can be diverse.
More variants of the pattern exist, often observed in company contexts. An
Enterprise API is an API that is available within a company-internal network only. A
Product API ships with purchased software (or open-source software). Finally, Ser-
vice APIs exposed by cloud providers and the application services hosted in cloud
environments also qualify as variants of Community API if access to them is limited
and secured.
The target audience size, location, and technical preferences play a role, too (often
even related to the budget considerations, as members of the community might pay
for the API). These community characteristics might be significantly more challeng-
ing and more diverse than those of individual teams or the public. In contrast to a
Public API, where the API development organization often can set standards easily
because the users are politically relatively weak, stakeholder concerns in bounded
communities are often diverse and demanding. For example, the concerns of roles
such as application owner, DevOps staff, IT security officer, and so on, might differ
and conflict with each other. These considerations might also make API life-cycle
management more demanding. For example, a paying customer of a Community
API might have rather strong demands that an API version remains in operation.
Finally, the decision option with the most limited visibility is Solution-Internal
API.
As for the prior two patterns, the budget must be considered to fund the develop-
ment, operations, and maintenance of the Solution-Internal API. This is usually
less problematic for Solution-Internal APIs than for the two other API visibility
types (which are more exposed) because a single project or product budget typically
covers the costs of the API. This, in turn, means that the project can also decide
about life-cycle considerations and supported target audience size, location, and
technical preferences. Naturally, the significance of these concerns depends on the
project goals. For example, consider an internal API developed to invoice product
purchases in an online shop. It can be expected that the products and their billing
requirements are known to the API development team; they change over time. If the
team rolls out a new API version, it can notify the dependent teams, working on the
same shop application, about the change.
Other technical concerns raised previously have a similar character. Workloads
are typically better known than in Public APIs unless the Solution-Internal API
receives its calls from a Public API. For example, in the billing scenario, if all com-
pany products themselves are offered via Public APIs, then the Solution-Internal
API for billing has to cope with the loads coming from those Public APIs. Likewise,
the complexity and maturity of backend systems and data stores, as well as security
demands, have to fulfill only solution-internal demands and can follow best practices
used in the organization that offers them.
Note that sometimes Solution-Internal APIs evolve into Community APIs (or
even Public APIs). Such graduation should not just happen as a form of scope creep
but should be decided and planned consciously. Some API design decisions, such as
those about API security, might have to be revisited when such graduation happens.
Also note that API visibility includes message and data structure visibility. API
client and provider require a shared understanding of the data structures exchanged.
In domain-driven design terms, these data structures are part of the Published Lan-
guage [Evans 2003]. A rich Published Language has the potential to contribute to a
positive developer experience; however, it also introduces coupling inherently.
Sample decision outcome. How did the case study team at Lakeside Mutual
decide, and why?
In the context of the customer self-service channel,
facing the need to serve external users such as existing customers,
the API designers at Lakeside Mutual decided to evolve their SOLUTION-INTERNAL
API into a COMMUNITY API, neglecting PUBLIC API,
to be able to address the wants and needs of a known user population and predict
the API workload,
52 Chapter 3 API Decision Narratives
Figure 3.3 shows the two decision options, Frontend Integration (or vertical
integration) and Backend Integration (or horizontal integration).2
«Decision»
API Integration
Types
«Option» «Option»
integrate two or integrate frontend
more backends and backend
horizontally vertically
«Pattern» «Pattern»
Backend Frontend
Integration Integration
2. The notion of horizontal versus vertical integration originates from the common visualization of dis-
tributed systems (and their layers and tiers) that places frontends at the top of diagrams and backends
at the bottom.
Foundational API Decisions and Patterns 53
Both integration types can be combined with any of the visibility patterns
discussed earlier.
For many backend integrations, runtime qualities such as performance and scal-
ability have to be taken into account. For instance, some backends may in turn serve
multiple frontends, or large amounts of data might have to be transferred between
backends. Security might be an important consideration when backend integra-
tions across organizational boundaries are required. Similarly, interoperability is an
important force in some backend integration scenarios. For instance, application
owners and system integrators of the involved systems might not know each other.
For integration tasks, Backend Integration in particular, the development
budget might also be important to consider. As an example, the cost allocations of
Solution-Internal APIs and Community APIs may not be clear, and only limited
budgets can be spent on integration tasks. Integration of systems means that the
development cultures and company politics of the systems to be integrated might
clash or be incompatible.
For both patterns of this decision, Frontend Integration and Backend Inte-
gration, links to the decision options of the API visibility decision exist, such as the
following:
Sample decision outcome. Which Lakeside Mutual API design arose when going
through this decision?
In the context of the customer self-service channel,
facing the need to supply external users with correct data through a user interface,
the Frontend Integration pattern was chosen (and Backend Integration
neglected)
Foundational API Decisions and Patterns 55
to achieve high data quality and productivity gains when customers serve
themselves,
accepting that the external interface has to be secured properly.
HTTPS and the API Key pattern featured in a later decision are two options to
deal with the “accepting that” consequence stated in the sample decision outcome.
«Decision»
Documentation of
the API
«Option» «Option»
do not document the API provide a dedicated API
description for its
documentation
«Do Nothing»
No API «Pattern»
Description API Description «Pattern»
Interface
Description
The essential API-related pattern for this decision is API Description. A small or
simple project, or prototype projects that are likely to change significantly in the
near future, might choose not to apply this pattern and thus select the “no API
Description” option.
Decision: Documentation of the API
Should the API be documented? If so, how should it be documented?
56 Chapter 3 API Decision Narratives
An API Description contains the functional API contract that defines request
and response message structures, error reporting, and other relevant parts of the
technical knowledge to be shared between API provider and client. In addition to
this syntactical interface description, it contains quality management policies as well
as semantic specifications and organizational information. The API contract part is
essentially a special case or variant of the “Interface Description” pattern [Voelter
2004], with the purpose of describing an API. For example, OpenAPI Specification
(formerly known as Swagger), API Blueprint [API Blueprint 2022], Web Application
Description Language (WADL), and Web Services Description Language (WSDL)
are languages for specifying interfaces following the Interface Description pattern
that can be used to describe the technical part of the API Description, the API con-
tracts. Alternatively, more informal descriptions of the API contracts are possible,
too, for example, in textual form on a Web site. Both options, description language
and informal specification, can be combined. MDSL is an example of a machine-
readable language that supports the pattern (see Appendix C, “Microservice
Domain-Specific Language (MDSL)”).
The other parts mentioned in the pattern solution (quality management policies,
semantic specifications and organizational information, invocation sequences, pre-
and postconditions, invariants, and so on) are often described informally in practice.
For many of those, formal languages also exist, for example, to define pre- and post-
conditions and invariants [Meyer 1997] or invocation sequences [Pautasso 2016].
A key aspect of the pattern is that an API Description helps to enable interoper-
ability because it provides a common, programming-language-independent descrip-
tion of the API. In addition, it helps to support information hiding. Providers should
not unveil details about the implementation of the API that clients do not require.
At the same time, clients should not have to guess how to correctly invoke the API.
That is, API designers should care for the consumability and understandability of
Decisions about API Roles and Responsibilities 57
the API. A clear and precise API Description is essential to reach this goal. The API
Description can help to strike a balance between consumability, understandability,
and information hiding.
Independence of API implementation details helps ensure loose coupling of API
clients and providers. Both loose coupling and information hiding are essential to
enable extensibility and evolvability of the API. If clients are not highly dependent
on API implementation details, it is usually easy to change and evolve the API.
In Part 2, the visibility and integration patterns presented in this section appear in
Chapter 4, “Pattern Language Introduction.” API Description is featured in Chap-
ter 9, “Document and Communicate API Contracts.”
The drivers for API introduction and requirements for API design are diverse. As
a consequence, the roles that APIs play in applications and service ecosystems dif-
fer widely. Sometimes, an API client wants to inform the provider about an incident
or hand over some data; sometimes, a client requests provider-side data to continue
client-side processing. Sometimes, the provider has to perform a lot of complex
processing to satisfy the information needs of the client; sometimes, it can simply
return a data element that already exists as part of its application state. Some of the
provider-side processing, whether simple or complex, may change the provider-side
state, some might leave it untouched.
58 Chapter 3 API Decision Narratives
Once the role of an endpoint has been defined (action- or data-oriented), more
fine-grained decisions on the responsibilities of the endpoint operations are due.
Operations can solely compute results, only read state, create new state without
reading it, or realize a state transition. Clearly defining these responsibilities, for
instance, in an API Description, can help developers to better design and choose
deployment options for an API endpoint. For example, if only stateless computa-
tions and data reading are performed on an endpoint, their results can be cached and
the corresponding implementation can be replicated to scale out more easily.
As illustrated in the category overview in Figure 3.5, the responsibility category
contains two decisions. Usually, an (at least initial) architectural role decision is made
during endpoint identification, and then operation responsibilities are designed.
Note that architectural roles have to be decided for each endpoint (or resource),
whereas operation responsibilities should be assigned to each API operation.
«Category»
Responsibility
«Decision» «Decision»
Architectural Responsibility
Role of an API of an API
Endpoint «Next» Operation
Two main options can be chosen in this decision, illustrated in Figure 3.6.
«Category»
Responsibility
«Decision»
Architectural
Role of an API
Endpoint
«Option»
«Option»
a resource whose primary
a resource whose primary function is storage and
function is to process retrieval of data or metadata
incoming commands
«Pattern» «Pattern»
Processing Information
Resource Holder Resource
The basic decision between these two types of resources is relatively easy, as it is
based on the functionalities required by clients. However, there is much freedom to
determine which functions are offered on which resources and how to decompose
the API well. For instance, API designers have to consider contract expressiveness
and service granularity: simple interactions give the client good control and make
processing efficient, but action-oriented capabilities can promote qualities such as
consistency, compatibility, and evolvability. These design choices can be positive or
negative for the learnability and manageability of the API. Also, semantic interop-
erability (including a joined understanding of the meaning of the data exchanged)
must be ensured. If not done well, the chosen endpoint-operation layout can have a
negative impact on response time and lead to chatty APIs.
Decisions about API Roles and Responsibilities 61
A truly stateless Processing Resource can be hard to achieve in reality. API secu-
rity and request/response data privacy can lead to the need for maintaining state, for
example, when a full audit log of all API invocations and resulting server-side pro-
cessing has to be maintained.
The underlying impact on coupling should be considered, particularly for state-
ful resources. Highly data-centric approaches tend to lead to create, read, update,
delete (CRUD) APIs, which can negatively affect coupling. This is discussed later
in more detail for the different kinds of information holder roles. The structure of
some backends could lead to highly coupled APIs when followed as-is; however, API
designers are free to design the API as an additional layer specifically to support the
interactions between the API and its clients. Here, various quality attribute conflicts
and trade-offs specific for API design but also in relation to backend services are to
be considered, such as concurrency, consistency, data quality and integrity, recover-
ability, availability, and mutability (or immutability). Also, such decisions are often
dependent on compliance with architectural design principles such as loose coupling
[Fehling 2014], logical and physical data independence, or microservices tenets such
as independent deployability [Lewis 2014].
Sample decision outcome. How did our case study team resolve the forces of
concern?
In the context of the customer self-service channel at Lakeside Mutual,
facing the need to empower clients to update their contact information easily,
the integration architects at Lakeside Mutual decided to introduce a data-ori-
ented Information Holder and not an activity-oriented Processing Resource
to provide expressive, easy-to-understand create, read, update, and delete
functionality,
accepting that the exposure of contact information couples the self-service chan-
nel to the customer management backend to some extent.
Unlike operational data, master data is long-living and frequently referenced but
still mutable. A Master Data Holder stores such data. Here, master data quality is
often a central decision driver, including master data consistency and its protection,
for example, from attacks and data breaches. Very often, there are external depend-
encies such as data ownership by different organizational units that must be consid-
ered in the design of Master Data Holder resources as well.
For both Operational Data Holders and Master Data Holder, a simple
design is a CRUD resource for each identified interface element that exposes opera-
tional or master data. Use of the words “create, read, update, and delete” in the
preceding pattern sketches should not indicate that such designs are the intended
or only possible solution for realizing the patterns. Such designs quickly lead to
chatty APIs with bad performance and scalability properties. They can also lead to
unwanted coupling and complexity. Beware of such API designs! Instead, we recom-
mend an incremental approach during resource identification. It aims to first iden-
tify well-scoped interface elements such as Aggregate roots in domain-driven design
(DDD), business capabilities, or business processes. Even larger formations such as
Bounded Contexts may serve as starting points. In infrequent cases, domain Enti-
ties can also be considered to supply endpoint candidates. For a deeper discussion
on the relation of APIs and DDD, see [Singjai 2021a, 2021b, 2021c]. This approach
leads to Operational Data Holder and Master Data Holder designs that are
semantically richer. In DDD terms, on the domain model side, we aim for a rich and
deep domain model instead of an “anemic domain model” [Fowler 2003]; this model
should be reflected, but not necessarily mirrored in the API design.
For some data, also long-living, we know that clients do not want to or should not
be allowed to modify it. Such reference data should be offered via a Reference Data
Holder. Caching of this data is possible, which leads to high performance. If caching is
used, consistency versus performance trade-offs might have to be made. Since reference
data rarely changes if at all, there is a temptation to simply hardcode it within the API
clients or retrieve it once and then store a copy locally. Such designs violate the do not
repeat yourself (DRY) principle and work well only in the short run.
As a supporting role, there is the option to design Link Lookup Resources. They
are resources whose primary function is supporting clients that follow or derefer-
ence links to other resources. Links are a primary means to improve coupling and
Decisions about API Roles and Responsibilities 65
cohesion between API consumers and providers, but there is also the coupling to the
Link Lookup Resource to be considered. Links can also help to reduce message sizes
by placing a link in the message instead of the content, as in the Embedded Entity
pattern. But if clients need all or part of the information, this practice increases the
required number of calls. Both placing links in messages and including content in an
Embedded Entity influence the overall resource use. For links to work well, dynamic
endpoint references that can change at runtime should ideally be established. Link
Lookup Resources increase the number of endpoints in an API and can lead to
higher API complexity; the severity of consequence depends on how centralized or
decentralized Link Lookup Resources are. Finally, the consistency issue of dealing
with broken links has to be considered: a link lookup provides the option to deal
with the problem, whereas a broken link without a lookup usually immediately leads
to an exception (i.e., a “resource not found” error).
Sample decision outcome. The API designers at Lakeside Mutual decided for
data holder specializations as follows:
In the context of the Customer Management backend,
facing the need to keep and use customer data for a long time,
the API designers at Lakeside Mutual decided to use the Master Data Holder
pattern, introducing a Customer Core service, and neglected the other four types
of information holders,
to achieve a single consolidated view on customer data across systems,
accepting that this Master Data Holder might become a performance bottle-
neck and single point of failure if it is not architected and implemented properly.
«Pattern» «Pattern»
Computation State Creation
Function Operation
«Option»
«Option»
an operation that computes a an operation that
result solely from the input creates states on an
and does not read or write API endpoint and is in
server-side state essence write-only
«Decision»
Responsibility
of an API
Operation
«Option» «Option»
an operation that performs a read-only operation that
one or more activities only finds and delivers data
causing a server-side state without allowing clients to
change change it
«Pattern» «Pattern»
State Transition Retrieval
Operation Operation
The first pattern is State Creation Operation, modeling an operation that cre-
ates states on an API endpoint and is, in essence, write-only. Here, in essence means
that such operations might need to read some provider-internal state—for example,
to check for duplicate keys in existing data before creation. However, their main pur-
pose is state creation.
In the design of State Creation Operations, their impact on coupling should be
considered. Because the provider state is not read, it can become difficult to ensure
consistency. As incidents that clients report happen before they arrive at the provider,
timing needs to be considered in the design as well. Finally, reliability is an important
concern, as messages might appear in a different order or be duplicated at the API
provider.
68 Chapter 3 API Decision Narratives
A A’
The selection of this pattern has the following decision drivers: service granularity is
essential to consider, as large services may contain complex and rich state information,
updated only in a few transitions, while smaller ones may be simple but chatty in terms
of their state transitions. For longer-running process instances, it can be difficult to
keep the client-side state and the states of provider-side backends consistent. In addi-
tion, it is important to consider whether there are dependencies on state changes made
earlier in the process. For example, system transactions triggered by other API clients,
by external events in downstream systems, or by provider-internal batch jobs might
collide with a state change triggered by a State Transition Operation. There is a
trade-off between the two goals of network efficiency and data parsimony: the smaller
messages are, the more messages have to be exchanged to reach a particular goal.
A A’
• What is the optimal number of API message parameters and body parts and an
adequate structure of these representation elements?
• What are the meaning and stereotypes of the representation elements?
For instance, regarding the first question, an HTTP resource API typically uses
the message body to send data to or receive data from the provider (for instance,
rendered as JSON, XML, or another MIME type), and the query parameters of
the URI specify the requested data. In a WSDL/SOAP context, we can interpret this
design issue as how the SOAP message parts should be organized and which data
types should be used to define the corresponding elements in the XML Schema Defi-
nition (XSD). In gRPC, this design issue is about the message structure defined with
Protocol Buffer specifications, for example containing details such as messages and
data types.
Selecting Message Representation Patterns 71
Decisions for this category likely have to be made whenever a message is designed
or refactored. The representation elements transported in the message, including
request parameters and body elements, are considerations in these decisions.
As illustrated in Figure 3.9, this category contains four typical decisions. The first
is on the structure of the parameter representation. Based on this representation, it
can be decided what the meaning and responsibility of message elements are. Next,
it can also be decided whether multiple data elements require additional informa-
tion. Finally, the whole message can or cannot be extended with context information.
«Optional Next»
«Decision»
Subset of High
Number and
Data Records
with the Same
Structure
Required
Figure 3.10 illustrates the typical decision-making options for this decision.
«Pattern» «Pattern»
Atomic Atomic
Parameter Parameter List
«Option» «Option»
scalar representation list representation
«Decision»
Structure of
Parameter
Representation
«Option» «Option»
complex complex representation
representation with with multiple root
one root element elements
«Pattern» «Pattern»
Parameter Tree Parameter Forest
If neither option (scalar or list representation) is applicable, one of two more com-
plex representations should be chosen. If a single root element is present in the data
or can easily be designed for the data to be transmitted, the representation elements
can be wrapped in a hierarchical structure following the Parameter Tree pattern.
As any complex data structure can be placed under a single root element, the
Parameter Tree option is always applicable but might not make much sense if the
data elements are rather unrelated contentwise. If a single tree structure feels awk-
ward or artificial for the data elements to be transmitted, several trees can be grouped
into a list of such structures in the Parameter Forest pattern.
74 Chapter 3 API Decision Narratives
The more complex patterns in this category all use Atomic Parameters to build
up more complex structures. That is, Atomic Parameter List is a sequence of
Atomic Parameters, and the tree leaves in a Parameter Tree are Atomic Param-
eters. The structures in a Parameter Forest are built using the other three pat-
terns. Those uses relations between the patterns are illustrated in Figure 3.11. As
a consequence, the two decisions explained previously need to be recursively made
again for the detailed structures in the complex patterns. For instance, for each data
structure in a Parameter Tree, it must be decided again whether this structure itself
is represented as a scalar, list, or tree. The technology mappings of the patterns are
discussed in Chapter 4.
An Atomic Parameter List can be represented as a Parameter Tree as a wrap-
per structure for transport if the technology used supports no other way to transport
multiple flat parameters. Such a tree has only scalar leaves underneath its root.
There are several shared decision drivers when selecting among the four patterns
in the structure of parameter representation decision.
One obvious force is the inherent structure of the domain model and the system
behavior. To ensure understandability and simplicity, and to avoid unnecessary com-
plexity, it is advisable to stay close to the domain model, both in the code and in
parameter representations in messages. It is important to apply this general advice
carefully—only data that the receiver wants should be exposed to avoid unneces-
sary coupling. For instance, if the domain data element structure is a tree, apply-
ing Parameter Tree is a natural choice, enabling easy traceability from domain
model or programming language data structures to message structures. Similarly,
the intended behavior should be reflected closely: For an Internet of Things (IoT)
scenario in which a sensor sends one data item frequently to an edge node, the most
natural choice is an Atomic Parameter. Decisions on the number of messages and
on each message structure require a careful analysis of when which data element
is required. Sometimes this cannot be deduced analytically, and extensive testing is
required to optimize the message structures.
Selecting Message Representation Patterns 75
«Pattern»
Parameter Forest
«Uses»
«Can Use»
as wrapper «Uses»
structure for
«Pattern» transport «Pattern»
Parameter Tree Atomic
Parameter
«Uses»
All kinds of additional data to be transmitted with the message, such as security-
related data (for example, security tokens) or other metadata (for example, message
and correlation identifiers or error codes), have to be considered here as well. Such
extra information can actually change the structural representation of the message.
For instance, if metadata has to be sent in addition to a Parameter Tree, it might
make sense not to integrate the metadata in the tree but to use a Parameter Forest
with two top-level tree elements instead, the message content and the metadata.
It is not always necessary to transmit entire data elements available in an under-
lying business logic or domain model. To enable better performance, only the rel-
evant parts of the data elements should be transmitted. This optimizes the resource
use (less bandwidth usage and lower memory consumption) and performance of
message processing. For instance, if a client requires salary data stored in a set of
employee data records to perform calculations unrelated to the specific employee,
76 Chapter 3 API Decision Narratives
one could simply transmit all those records in a Parameter Tree. But as only the sal-
ary numbers are needed, sending only those numbers in an Atomic Parameter List
would greatly reduce the message size.
On the other hand, breaking apart data into too many small messages can also
negatively impact resource use, as it increases the network traffic and needs more
bandwidth overall. Thus, a high number of small messages might require more per-
formance for processing many messages overall. This situation gets even worse if the
server has to restore the session state each time a message is processed. For instance,
if the client in the preceding example requires other data from the set of employee
records shortly after the first calculation and sends several successive requests, the
total resource use and performance might be much worse than if the whole set of
selected employee records had been transmitted in the first place.
Sometimes, a number of data elements can be grouped and sent in one message,
again to improve resource use and performance. For instance, if an edge node of a
cloud-based IoT solution collects data from sensors (such as a set of measurements
in a certain time interval), it often makes sense to send this data to the cloud core in
batches rather than sending each data element separately. When performing precal-
culations on the edge, their results might even fit into single Atomic Parameters.
Considering the cacheability and mutability of message payload can help to
improve performance and resource consumption.
Optimizing resource use and performance may have a negative influence on other
qualities, such as understandability, simplicity, and complexity. For instance, an API
that offers one message per specific task to be performed on an employee record
would contain many more operations in the API endpoint than an alternative design
that just allows for transmitting a specified set of employee records in their entirety.
The former option might have a better resource utilization and performance, but the
API design is also much more complex and thus harder to understand.
The request and response message structures are important elements of the API
contract between API provider and API client; they contribute to the shared knowl-
edge of the communication participants. This shared knowledge determines part of
the coupling between API provider and API client, which is discussed as the format
autonomy aspect of loose coupling [Fehling 2014]. For example, one could consider
always exchanging strings or key-value pairs, but such generic solutions increase
the knowledge that is implicitly shared between consumer and provider, leading to
stronger coupling. This would complicate testing and maintenance. It also might
bloat the message content unnecessarily.
Sometimes, only few data elements have to be exchanged in message structures to
satisfy the information needs of the communication participants, for instance, when
checking the status of a processing resource (in the form of a distinct value defined
Selecting Message Representation Patterns 77
a negative impact on the stability of the API design. Important design considerations
that are hard to get right in the first place are involved, one reason being the uncer-
tainty about (future) use cases that API providers and API clients often experience.
Note that in addition to the more conceptual considerations called out in this sec-
tion, many technology decisions also have to be made. This includes supported com-
munication protocols (HTTP, HTTPS, AMQP, FTP, SMTP, and so on) and message
exchange formats such as JSON, SOAP or plain XML, ASN.1 [Dubuisson 2001],
Protocol Buffers [Google 2008], Apache Avro schemas [Apache 2021a], or Apache
Thrift [Apache 2021b]. API query languages such as GraphQL [GraphQL 2021] can
also be introduced.
Element Stereotypes
The decision on the structure of parameters, explained earlier, defines the data trans-
fer representations (DTRs) for request and response messages. However, this deci-
sion does not yet define the meaning of the individual representation elements. Four
element stereotype patterns, shown in Figure 3.12, define the typical design options
for the element stereotypes decision.
«Decision»
Meaning of
Stereotypes of
Message
Elements
There are several decision drivers that apply to any kind of Data Element. When
designing API elements that represent data-centered domain elements such as Enti-
ties, the simplest and most expressive way to map them to APIs is to represent the
Entity fully in the API. Often this is not a good idea, as it increases the number of
processing options for communication participants, which limits the ease of process-
ing the data. Interoperability can be at risk, and API documentation effort increases.
80 Chapter 3 API Decision Narratives
The key decision drivers for Metadata Elements are similar to the ones for
ordinary Data Elements. However, a number of specific additional aspects have to
be considered. If data travels with corresponding type, version, and author infor-
mation, the receiver can use this extra information to resolve ambiguities, which
improves interoperability. If runtime data is accompanied by additional explanatory
data, it becomes easier to interpret and process; on the other hand, this may increase
coupling between the communication parties. To improve ease of use, Metadata
Elements may help the message recipient to understand the message content and
process it efficiently. But messages become larger when Metadata Elements are
included, so runtime efficiency may be negatively affected.
A type of Data Element with a special meaning or responsibility are those ele-
ments that signify identifiers.
Selecting Message Representation Patterns 81
Pattern: id ELEmEnt
Problem How can API elements be distinguished from each other at design time and
at runtime? When applying domain-driven design, how can elements of the
Published Language be identified?
Solution Introduce a special type of Data Element, a unique Id Element, to identify API
endpoints, operations, and message representation elements that have to be
distinguished from each other. Use these Id Elements consistently throughout
API Description and implementation. Decide whether an Id Element is globally
unique or valid only within the context of a particular API.
The Link Element pattern shares its decision drivers with Id Element, as essen-
tially all Link Elements are remotely accessible Id Elements. The opposite does
not hold; some identifiers used in APIs do not contain network-accessible addresses.
For example, consider a domain data element that should not be remotely acces-
sible by the client, but still has to be referenced (for instance, a key data element in
the backend or in a third-party system). In such a situation, a URI cannot be used.
It can be challenged whether or not such elements should be handed out to clients at
all. Sometimes this might be a bad design choice, whereas in other cases, it might be
necessary. Consider for instance a backend “Correlation Identifier” [Hohpe 2003] or
a proxy (surrogate) for a Correlation Identifier: it must be passed along to the client
in order to be applicable.
«Data Element»
«Data Element» customers
CustomerResponseDto
AddressDto
rstName: String
streetAddress: String lastName: String
postalCode: String
city: String «Id Element»
customerId: String
To let clients interact with the customer master data, the CustomerInforma-
tionHolder is implemented as an Information Holder Resource, specifically
a Master Data Holder that exposes several operations. In these operations, the
request and response messages transport different Data Elements, for example, of
customer data. The implementation classes are not exposed directly; instead, DTOs
are used. Unlike the entities, the DTOs also hold Id Elements and Link Elements
that let clients retrieve more data.
Because Lakeside Mutual serves a large number of customers, the result of the
getCustomers Retrieval Operation uses Pagination, a pattern we have not seen
so far, to let API clients navigate the data in manageable chunks.
Pagination and other patterns related to API quality are featured later in the next
two decision narratives.
84 Chapter 3 API Decision Narratives
How can we achieve a certain level of quality of the offered API while at the same
time utilizing the available resources in a cost-effective way?
The quality of an API has many dimensions, starting with the functionality
described in the API contract but also including reliability, performance, security,
and scalability. Some of these technical qualities are referred to as quality of service
(QoS) properties. QoS properties might be conflicting and almost always need to be
balanced with economic requirements such as cost or time to market.
The guaranteed QoS does not have to be the same for all clients. Most decisions
in this category have to be made for combinations of API clients and APIs accessed
by these clients. Many decisions can be made for large groups of these combina-
tions, such as all clients with freemium access to an API or all clients accessing a
specific API.
The main decisions related to quality governance are shown in Figure 3.14.
«Category»
Quality
«Decision» «Decision»
Handling of Avoid
Referenced Data Unnecessary Data
Transfer
«Decide for some instances of» «Decide for some instances of»
«Consider If Not
Decided Yet»
«Consider If Not «Consider If Not
Decided Yet» Decided Yet»
«Decision»
Client Identification
and Authentication
API quality has to be governed and, as needed, improved. In this section, we look
at governance and management; the next one suggests quality improvements. The
themes of the decisions about the patterns in this category are as follows:
«Option»
identification and
authentication via «Option»
«Pattern» «Decision» «Practice»
shared secret, secured authorization via
API Key Client Authorization
with secret key dedicated protocol
Combined with Identification Protocol
Secret Key and
Authentication
«Realizes» «Realizes»
«Practice»
Authentication
The first and simplest option is to decide that secure identification and authenti-
cation are not needed, which is suitable, for instance, in nonproduction system APIs;
for APIs in controlled, nonpublic networks with a limited number of clients; or for
Public APIs with a limited number of clients and no great risks in case of abuse or
excessive use.
The obvious alternative is to introduce an authentication mechanism for the API.
An API Key that identifies the client is a minimalistic solution to this problem.
If security is an important issue, API Keys are insufficient on their own. In con-
junction with an additional secret key that is not transmitted, API Keys can be used
to securely authenticate an API client. The API Key identifies the client, and an
Governing API Quality 87
additional signature made with the secret key, which is never transmitted, proves the
identity and ensures that the request was not tampered with.
Many complements and alternatives to API Keys exist, as security is a challeng-
ing, multifaceted topic. For instance, OAuth 2.0 [Hardt 2012] is an industry-standard
protocol for authorization that is also the foundation for secure authentication
through OpenID Connect [OpenID 2021]. Another example of a full-fledged authen-
tication or authorization protocol is Kerberos [Neuman 2005], an authentication
protocol that is often used inside a network to provide single sign-on. In combina-
tion with Lightweight Directory Access Protocol (LDAP) [Sermersheim 2006], it can
also provide authorization. LDAP itself also offers authentication features, so LDAP
can be used as authentication and/or authorization protocol. Examples of point-to-
point authentication protocols are Challenge-Handshake Authentication Protocol
(CHAP) [Simpson 1996] and Extensible Authentication Protocol (EAP) [Vollbrecht
2004].
A number of forces have to be considered in this decision. First of all, the level
of required security is important. If secure identification and authentication are
required, it is insufficient to choose either no secure identification and authentica-
tion needed or API Keys. API Keys help to establish basic security. Although they
require following a registration process, API Keys bring only a slight degradation in
terms of ease of use for clients once they have been obtained (compared to no secure
identification and authentication). The other options are less easy to use, as they
require dealing with more complex protocols and setting up the required services
and infrastructure. The management of user account credentials required in authen-
tication and authorization protocols can be tedious both on the client and provider
side; this is avoided in all options using API Keys, including its combination with a
secret key.
With regard to performance, the decision that secure identification and authenti-
cation is not needed has no overhead. API Keys have a slight overhead for processing
the keys, and their combination with a secret key requires some more processing
slightly reducing the performance. Authentication and authorization protocols tend
to have more overhead, as they also offer additional features (such as contacting a
trusted third party in Kerberos or authorization in OAuth or LDAP). Finally, the API
Key option decouples the client making an API call from the client’s organization,
as using the customer’s account credentials would needlessly give system administra-
tors and developers full account access. This problem could be mitigated in authenti-
cation and authorization protocols by establishing subaccount credentials that only
enable API access for an API client but do not offer any other privileges of the cus-
tomer’s account.
88 Chapter 3 API Decision Narratives
$$$
«Decision»
Metering and
Charging for API
Consumption
«Option» «Option»
Yes No «Consider If Not Decided Yet»
«Pattern» «Practice»
Rate Limit Authentication
«Can Use»
«Pattern» «Pattern»
Pricing Plan Freemium Model
«Can Be Combined With»
The major drivers for this decision are usually economic aspects, such as pric-
ing models and selecting a variant of the pattern that best suits the business model.
The benefits of applying the pattern should be contrasted with the efforts and
costs required to meter and charge customers. Accuracy is central, as API custom-
ers expect to be billed only for the services they actually have consumed. Accurate
metering requires an adequate meter granularity. Because metering and charging
records contain sensitive information about customers, extra protection has to be
provided to ensure security.
The alternative to using Rate Limits is to do nothing to prevent API clients from
excessive API usage. This makes sense in situations in which the problem is assessed
as unlikely to turn into a severe issue. For example, if all clients are in-house clients
or trusted partners, the overhead of a Rate Limit might not be justified.
The two alternatives, as well as the link to client identification and authentication
(and the authentication practices), are shown in Figure 3.18.
«Decision»
Preventing API
Clients From
Excessive
Usage
«Can Use»
«Practice»
Authentication
Figure 3.18 Prevent API clients from excessive API usage decision
The major forces to be considered in this decision are as follows: A certain level of
performance has to be maintained by the provider (sometimes even formally guaran-
teed in a Service Level Agreement); performance could be compromised if clients
abuse the API. Means for supporting client awareness of Rate Limits are required so
that clients can find out how much of their limits they have used up at a given point
in time. Establishing Rate Limits helps the provider to support qualities related to
reliability because they make it harder for clients to abuse the API in a way that puts
these qualities at risk. All these potential benefits must be contrasted to the impact
92 Chapter 3 API Decision Narratives
and severity of risks of API abuse and economic aspects. Introducing Rate Limits
produces costs and can be perceived negatively by clients. Thus, it has to be judged
whether the risks of API abuse imposed by a few clients are higher than the risks and
costs associated with introducing Rate Limits for all clients.
There are a number of typical variants of the pattern: SLAs only used for internal
use, SLAs with formally specified SLOs, and SLAs with only informally specified
SLOs.
«Decision»
«Pattern» «Pattern» «Pattern» Explicit
Rate Limit Pricing Plan API Description Specification of
Quality
Objectives and
Penalties
«Option» «Option»
Yes No
«Can Use» «Can Use» «Can Use» «Consider If Not Decided Yet»
«Practice»
SLA with SLA with SLA only for
Authentication
formally informally internal use
specified SLOs specified SLOs
Figure 3.19 SLAs and explicit specification of quality objectives and penalties decision
A Pricing Plan and Rate Limit should refer to the Service Level Agreement if
it is used. Like these patterns, a Service Level Agreement requires means for iden-
tifying and authenticating clients; usually, authentication practices such as API Keys
or authentication protocols have to be used as well.
Several main decision drivers steer this decision. It relates to business agility and
vitality, as the business model of an API client might rely on one or more of the pre-
viously named qualities of a particular service. Attractiveness from the consumer’s
point of view can be higher if guarantees about qualities are provided and commu-
nicated to the client. However, this must be contrasted with possible issues related to
cost-efficiency and business risks from a provider point of view. Some guarantees are
required by government regulations and legal obligations, such as those related to
personal data protection. Typical aspects that are candidates for guarantees in SLAs
are availability, performance, and security.
94 Chapter 3 API Decision Narratives
Note that some architectural decisions typically are revised as a product or service
evolves. In our insurance case, an SLA is actually introduced at a later stage, as we
will see in the presentation of the SLA pattern in Chapter 9.
Communication of Errors
A common quality concern for APIs is how to report and handle errors, as this has
direct impacts on aspects such as avoiding and fixing defects, costs of defect fixing,
robustness and reliability problems due to unfixed defects, and so on. If an error
occurs on the provider side, it can be due to an incorrect request, invalid permissions,
or numerous other problems that could be the fault of the client, the API implemen-
tation, or the underlying IT infrastructure.
One option is not to report (and then handle) an error at all, but this is usually
not advisable. A common solution if only one protocol stack is used (such as HTTP
over TCP/IP) is to leverage the error-reporting mechanisms of these protocols, for
instance, status codes in HTTP (protocol-level error codes). This does not work
if error reporting has to cover multiple protocols, formats, and platforms. In such
cases, the Error Report pattern is eligible.
The decision is illustrated in Figure 3.20. The main decision drivers to introduce
any kind of error reporting are the help in fixing defects and the increased robust-
ness and reliability that this promises. Error reporting leads to better maintain-
ability and evolvability. Detailed explanations of errors reduce the effort to locate
the root cause of a defect; consequently, the Error Report pattern often is more
effective than simple error codes. The target audiences of fault information include
developers and operators, but also help desk and other supporting personnel.
Thus, Error Reports should be designed to reach high expressiveness and achieve
meeting the target audience’s expectations. Error Reports are usually designed
to score well with regard to interoperability and portability, compared to simple
error codes. However, rather elaborate error messages can reveal information that
is problematic with regard to security, as disclosing more information about sys-
tem internals opens up attack vectors. An Error Report requires more work if
internationalization is required because the more detailed information contained
in the Error Report has to be translated.
«Decision»
Communication
of Errors
«Do Nothing»
Error Reporting Protocol-Level
Do Nothing
Error Codes
«Can Be Combined With»
«Decision»
Exchange of
Context
Information
Required
«Option» «Option»
Yes No
This decision narrative covered the theme API quality governance; the next set of
decisions aims at improving certain qualities, such as performance.
Pagination
Sometimes complex representation elements can contain large amounts of data that
is repetitive in nature (for instance, record sets). If only a subset of this information
at a time is required at the client, it might be better to send the information in small
chunks rather than in one large transmission. For example, consider thousands of
records being contained in the data, but a client displaying the information pagewise
with 20 records per page; user input is required to advance to the next page. Display-
ing only the current page and maybe prefetching one or two pages in either stepping
direction might be far more efficient in terms of performance and bandwidth use
than downloading all data records before even starting to display the data.
Deciding for API Quality Improvements 99
The starting point is that API designers have decided to apply either Parame-
ter Tree or Parameter Forest. Both patterns are used to represent complex data
records. In such cases, the designers should think about the following decision (illus-
trated in Figure 3.22):
«Pattern» «Pattern»
Parameter Tree Parameter Forest
«Decision»
Subset of High Number of Data
Records with the Same Structure
Required
«Option» «Option»
Yes No
«Pattern»
Pagination «Do Nothing»
Do Nothing
«Has Variant»
«Has Variant» «Has Variant» «Has Variant»
Pattern: Pagination
Problem How can an API provider deliver large sequences of structured data without
overwhelming clients?
Solution Divide large response data sets into manageable and easy-to-transmit chunks
(also known as pages). Send one chunk of partial results per response message,
and inform the client about the total and/or remaining number of chunks. Provide
optional filtering capabilities to allow clients to request a particular selection of
results. For extra convenience, include a reference to the next chunk/page from the
current one.
«Pattern»
Pagination
The pattern has the following relations to the patterns presented earlier:
• An Atomic Parameter List is usually used for its request message containing
the query parameters.
Deciding for API Quality Improvements 101
• A Parameter Tree or a Parameter Forest is usually used for the data struc-
turing in its response messages.
There are several key decision drivers when applying Pagination. The structure
of data elements or of the additional data that have to be sent with the message
needs to be repetitive in nature (contain data records, that is). The variability of the
data should be considered: Are all data elements identically structured? How often
do data definitions change?
Pagination aims to substantially improve resource consumption and perfor-
mance by sending only the data needed at the moment as fast as possible to the API
client. A single large response message might be inefficient to exchange and process.
In this context, data set size and data access profile (derived from the user wants
and needs), especially the number of data records required to be available to an API
client (immediately and over time), have to be considered. Especially when returning
data for human consumption, not all data may be needed immediately.
Also related to resource consumption, the memory available for a request (on both
API provider and API client sides) as well as the capacity of the network have to be
considered. Network and endpoint processing capabilities should be used efficiently,
but all results should be transferred and processed accurately and consistently.
Common text-based message exchange formats (for instance, expressively tagged
XML or JSON) incur high parsing costs and transfer data size due to verbosity and
overhead of the textual representations of the data. Some of this overhead can be
significantly reduced by using binary formats such as Apache Avro or Protocol Buff-
ers. However, many of these formats require dedicated serialization/deserialization
libraries, which may not be available in all consumer environments, for example, API
clients in Web browsers. The pattern is particularly eligible in such cases.
102 Chapter 3 API Decision Narratives
API providers often serve many different clients. It can be hard to design API oper-
ations that provide exactly the data required by all these clients. Some of them might
use only a subset of the data offered by the operations; other clients might expect
more data. The information need might not be predictable before runtime. A possi-
ble way to solve this problem is to let the client inform the provider at runtime about
its data fetching preferences. A simple option to do this is to let the client send a list
of its desires.
A simple list of wishes is not always easy to specify, for example, if a client wants
to request only certain fractions of deeply nested or repetitive parameter structures.
An alternative solution that works better for complex parameters is to let the client
send a template (or mock object) expressing the wishes as examples in its request.
While Wish Lists are typically specified as Atomic Parameter Lists and lead to
a reply based on a Parameter Tree, Wish Template typically performs the specifi-
cation of the wish in a mock Parameter Tree whose structure is also used for the
response.
104 Chapter 3 API Decision Narratives
For example, the provider could supply a fingerprint for each resource accessed,
which the client can then include in a subsequent request to indicate which “version”
of the resource it already has cached locally so that only newer versions are sent.
In other situations, an analysis of the usage of the already-deployed API might
reveal that clients are issuing many similar requests and that individual responses are
returned for one or more of these calls. These batches of requests may have a nega-
tive impact on scalability and throughput. In such situations, the Request Bundle
pattern is eligible.
Figure 3.24 summarizes the decision on how to avoid unnecessary data transfer.
«Decision»
Avoid
Unnecessary
Data Transfer
«Option»
No data transfer «Option» «Option» «Option» «Option»
reduction Use simple list to Use a structured Make data transfer Bundle multiple
possible or convey which template to dependent on a requests in a container
wanted information is convey which condition in the message
required information is request
required
«Pattern»
Rate Limit
For many operations, no data transfer reduction is possible or wanted for the
target operation(s). Alternatively, unnecessary data transfer can be avoided through
one of the two patterns Wish List and Wish Template, which both inform the pro-
vider about required data at runtime. Other alternatives are Conditional Request
to avoid repeated responses to the same requests and Request Bundle to aggregate
multiple requests in a single message.
The combination of Conditional Request with either Wish List or Wish Tem-
plate is a rather useful choice to indicate which subset of resources is requested in
case the condition evaluation states that the resource should be sent again. Request
Bundle can in principle be combined with each of the prior alternatives Condi-
tional Request or either Wish List or Wish Template. However, a combination
of two or even three of the patterns increases the complexity of the API design
and programming substantially for rather little gains, as all four patterns influence
a similar set of desired qualities positively. Figure 3.25 shows the possible pattern
combinations.
106 Chapter 3 API Decision Narratives
«Pattern»
Request Bundle
«Pattern» «Pattern»
Wish List Wish Template
«Can Be Combined With» «Can Be Combined With»
The main decision driver for this decision concerns the individual information
needs of clients, which have to be analyzed in order to find out which of the patterns
(and maybe even which combinations) are applicable and promise to have enough
benefits. Consider situations where data transfer over the network is perceived as a
potential bottleneck. In such cases, data parsimony can further drive the decision.
Data parsimony is an important general design principle in distributed systems, and
the four patterns can help to enhance parsimonious ways of data transmission.
Selecting any of the four patterns usually has a positive influence on the Rate
Limit and on bandwidth use, as less data is transferred. This likely will also improve
the performance, as transferring all data elements to all clients all the time, even
to clients that have only a limited or minimal information need, wastes resources
(including response time, throughput, and processing time).
Security can be a driver not to apply the patterns Wish List and Wish Template.
Enabling clients to provide options regarding which data to receive may unwit-
tingly expose sensitive data to unexpected requests or generally open up additional
attack vectors. For instance, sending long data element lists or using invalid attribute
Deciding for API Quality Improvements 107
Sample decision outcome. How does the Lakeside Mutual APIs provide a suited
message granularity and call frequency? The architects and designers chose
patterns as follows:
In the context of the Customer Management frontend for staff and agent use
cases,
having to deal with large amounts of customer records,
the API designers at Lakeside Mutual selected the Wish List pattern and did not
pick any other pattern from this section
so that response messages are small,
accepting that the wishes have to be prepared on the client side and processed on
the provider side, and that additional metadata is required.
Closely related to the decisions about message size optimization is the decision
about inlining or splitting structured data (complex data with multifaceted relations
between its parts, that is). We investigate two alternative patterns tackling this design
issue next.
There are two major options for this decision, shown in Figure 3.26.
«Pattern»
Data Element
«Optional Next»
«Decision»
Handling of
Referenced Data
«Option»
Links are provided to
«Option» look referenced data
Referenced data is up with separate calls
«Pattern» embedded in the
Embedded Entity message representation
«Pattern»
Linked
Information
Holder
«Can Use»
for providing an additional level
of indirection to decouple
«Requires»
resource clients and providers
«Pattern» «Pattern»
Link Lookup Resource Link Element
«Requires»
One option to address this problem is to embed the data of the referenced data
record in the Data Element to be sent over the wire.
The alternative is to make the referenced data accessible remotely and point at it,
introducing a Link Element to the message:
Figure 3.26 illustrates that this pattern can use a Link Lookup Resource for pro-
viding an additional level of indirection to decouple resource clients and providers.
Both Linked Information Holder and Link Lookup Resource require the use of
Link Elements.
It is possible to combine the two patterns, for instance, when using a top-level
Embedded Entity that itself uses Linked Information Holders for (some of) its
referenced data records.
As decision drivers, performance and scalability often play a major role. Both
message size and the number of calls required to perform an integration should be
low, but these two desires stand in conflict with each other.
Modifiability and flexibility have to be considered as well: information elements
contained in structured self-contained data might be hard to change because any
local updates have to be coordinated and synchronized with updates to related data
structures and the API operations that send and receive them. Structured data that
contains references to external resources usually is even harder to change than self-
contained data as there are more consequences and (external) dependencies for
clients.
Embedded Entity data sometimes gets stored for a while, whereas links always
refer to the latest updates in the data. Thus, accessing data when it is needed via links
is positive for data quality, data freshness, and data consistency. In terms of data
privacy, a relationship source and target might have different protection needs—for
example, a person and the credit card information belonging to this person. This
has to be considered, for instance, before embedding the credit card information in a
message requesting the person’s data.
110 Chapter 3 API Decision Narratives
Sample decision outcome. Does Lakeside Mutual prefer many small or few large
messages? They decided as follows:
In the context of the customer self-service channel,
facing the need to expose the customer aggregate that contains two entities (and
works with two database tables), the API designers at Lakeside Mutual decided
to use the Embedded Entity pattern
and neglected Linked Information Holder
so that all related data is transmitted in a single request,
accepting that the address data is transferred although not needed in some use
cases.
The patterns API Key, Context Representation, and Error Report are used
mainly in the elaboration (or Define) phase, which is covered in Chapter 6, “Design
Request and Response Message Representations.” Chapter 7, “Refine Message
Design for Quality,” then covers the construction (or Design) phase, containing the
patterns Conditional Request, Request Bundle, Wish List, Wish Template,
Embedded Entity, and Linked Information Holder. Finally, the Pricing Plan,
Rate Limit, and Service Level Agreement patterns are covered in Chapter 9, as
they mainly concern the transition phase of an API.
This completes the coverage of decisions and pattern options about API quality
(in this book). Next, we identify decisions required and patterns available to organ-
ize API evolution.
API providers and clients have to balance different, conflicting concerns in order
to follow their own life cycles; a certain amount of autonomy is required to avoid
tight coupling between them. In response to this conflict, the patterns presented here
jointly support API owners, designers, and users who seek to answer the following
question:
What are the governing rules balancing stability and compatibility with maintain-
ability and extensibility during API evolution?
As illustrated in Figure 3.27, API evolution centers around three decisions. The
first is whether the API supports some explicitly defined version identification
scheme, and if so, how version information is exchanged. The second decision is
on when and how new versions of an API should be introduced and old versions are
decommissioned. It offers three alternative strategies as decision options. Finally, it
can be decided whether or not any of the three strategies is augmented with an addi-
tional experimental preview. All those decisions are typically made at the API level.
«Category»
Evolution
«Decide for some instances of» «Decide for some instances of» «Decide for some instances of»
«Basic Concept»
API
Figure 3.28 illustrates the typical options for this decision. First, it has to be
decided whether an explicit version identification and transmission scheme is used.
The pattern Version Identifier covers this option. Next, Semantic Versioning
describes the use of a structured Version Identifier that separates breaking from
non-breaking changes.
«Option»
Define no scheme for «Option» «Option»
version identification and Use well-known,
Use an explicit version identification
transmission structured version
and transmission scheme
identifier
«Can Use»
to transmit identifier in a message
«Pattern»
Metadata
Element
exactness of identification. When an API uses it, its clients can rely on the syntax and
semantics defined in the specified API version; the message exchanges are interoper-
able as long as the Version Identifier stays the same. This way, client-side impact is
minimized: the client can safely assume that “breaking changes” will only be intro-
duced in subsequent versions. Furthermore, API providers want to avoid accidentally
breaking compatibility: if a Version Identifier is part of the message, recipients
can reject a message with an unknown version number. Finally, explicit versioning
makes it easier for API providers to manage their APIs, as it provides traceability of
API versions in use: API providers can monitor how many and which clients depend
on a particular API version.
Version Identifiers should be accurate and exact. Breaking changes will require
changes to the clients; thus, they are closely linked to considerations about the cli-
ent-side impact of software evolution steps. To make it impossible to accidentally
break backward compatibility, recipients should be able to reject a message based on
unknown version numbers. Finally, it should be considered that Version Identifiers
can help to establish traceability of API versions in use.
to achieve that breaking changes are spotted as soon as possible and maintenance
is eased,
accepting that metadata has to be transmitted and API descriptions require
updates as versions evolve.
Figure 3.29 illustrates the typical choices for this decision. The patterns explained
in this section are alternative options, providing different strategies to introduce and
decommission versions.
«Option»
Support two or more «Option» «Option»
incompatible versions of Support API Decommission API versions
the API in production at versions for a as early as possible
any time predefined lifetime
v1.1
Pattern: LimitEd LifEtimE guarantEE
Problem How can a provider let clients know for how long they can rely on the published
version of an API?
Solution As an API provider, guarantee to not break the published API for a fixed
timeframe. Label each API version with an expiration date.
Applying this pattern means that a limited number of API versions are kept in
production. The goal is to guarantee that API changes do not lead to undetected
backward-compatibility problems between clients and the provider, especially with
regard to their semantics. It does so through a compromise: changes to the client
caused by API changes are minimized as multiple versions are supported, and clients
can stay on the last version for a defined time. But the pattern also limits the number
of API versions supported by API providers, thereby minimizing the maintenance
effort for supporting clients relying on these API versions. Thus, the pattern guaran-
tees that API changes do not lead to undetected backward-compatibility problems
between clients and the provider.
Limited Lifetime Guarantee achieves this combination of force impacts through
a concrete date in the lifetime guarantee that helps to make client-side changes caused
by API changes more plannable. It also limits the maintenance effort to support old
clients that API providers have to plan for.
The Aggressive Obsolescence pattern can be used for phasing out existing fea-
tures as early as possible.
v1.3 v2.1
When releasing a new API version, the oldest one that still runs in production is
retired (which is the second last one by default). As a variant, more than two ver-
sions—for instance, three—can be supported. In such cases, the pattern variant “N
in Production” is chosen. To maintain the character and benefits of this pattern,
however, it is crucial that the number N remains small.
Two in Production allows the API provider and the client to follow different
life cycles so that a provider can roll out a new API version without breaking clients
using the previous API version. Two in Production’s impact on forces resolution is
similar to that of Limited Lifetime Guarantee. The difference is that two (or in the
general case, N) version are supported in parallel, which brings a sound compromise
to the goal conflicts between clients and provider. As an additional benefit for provid-
ers, the pattern enables the ability to roll back to an old API version if a new version
is not accepted by clients due to bugs, poor performance, or a dissatisfying developer
experience.
118 Chapter 3 API Decision Narratives
Finally, to ease the design of new APIs, gain experience, and gather feedback, the
Experimental Preview pattern can be applied to indicate that no API availability
and support guarantees are given, but the API can be used opportunistically with the
objective to gather feedback (provider) and learn early (client).
«Option»
Do not offer «Option»
API previews Offer API previews
This pattern can be applied to support innovations and new features. Such show-
casing raises the awareness of a new API (version), facilitates feedback, and gives
the customers time to decide whether to use the new API and initiate development
projects.
An Experimental Preview is an alternative to one or more official versions. It is
eligible when API providers do not want to manage and support many API versions
in order to focus their efforts.
Consumers want to learn early about new APIs or API versions so that they can
plan ahead, build innovative products, and influence the API design. With regard to
planning, clients especially want stable APIs in order to minimize change effort.
Decisions about API Evolution 119
v0.1
v1.2
?
Pattern: EXPErimEntaL PrEViEW
Problem How can providers make the introduction of a new API (version) less risky for
their clients and obtain early adopter feedback without having to freeze the API
design prematurely?
Solution Provide access to an API on a best-effort base without making any commitments
about the functionality offered, stability, and longevity. Clearly and explicitly
articulate this lack of API maturity to manage client expectations.
Sample decision outcome. The API product owner at Lakeside Mutual decided
as follows:
In the context of the offer quotation API in the policy management backend,
facing the need to support multiple API clients with different release cycles,
the API designers at Lakeside Mutual decided both for the Two in Production
pattern and the Experimental Preview pattern
to achieve that clients have a choice and gain time to migrate when breaking
changes arise (and can play with upcoming features),
accepting that two versions have to be operated and supported simultaneously.
The patterns on API evolution are covered in Chapter 8, “Evolve APIs”. They
mainly concern the transition phase (and later phases) of an API.
120 Chapter 3 API Decision Narratives
The returned response now contains only the requested fields (see the Wish List
pattern in Chapter 7, “Refine Message Design for Quality,” for the full example):
{
"customerId": "gktlipwhjr",
"birthday": "1989-12-31T23:00:00.000+0000",
"postalCode": "8640"
}
All operations are guarded by API Keys, which are represented by the Authori-
zation header in the preceding command. In the Customer Core service, several
requests can be combined into one as a Request Bundle. Failures are communicated
with Error Reports. In the following call, an invalid-customer-id is used:
An Error Report informs the client that this customer was not found:
{
"timestamp": "2022-02-17T11:03:58.517+00:00",
"status": 404,
"error": "Not Found",
"path": "/customer/invalid-customer-id"
}
Interlude: Quality and Evolution Patterns in the Lakeside Mutual Case 121
For more examples of API Keys and Error Reports, please refer to the pattern
texts in Chapter 6.
Many response messages contain either Embedded Entity or Linked Informa-
tion Holders. For example, in the Policy Management backend, the CustomerDto
contains a nested representation of all customer policies. However, many clients
may not be interested in the policies when they access the customer resource. To
avoid sending large messages containing lots of data that is not processed on the cli-
ent side, a Linked Information Holder is used that refers to a separate endpoint
returning the customer policies:
Summary
In this chapter, we identified pattern-related architectural decisions required during
API design and evolution, covering the following topics:
3. Are the Lakeside Mutual developers somewhat disconnected from the architects and the product owner
of this sample case?
Summary 123
The Patterns
This part of the book presents our catalog of patterns for API design and evolution.
Complementary to Chapter 3, “API Decision Narratives,” in Part 1, it does not have
to be read page by page but serves as a reference.
The catalog is organized along the four phases of the Align-Define-Design-Refine
(ADDR) process introduced in Principles of Web API Design: Delivering Value with
APIs and Microservices [Higginbotham 2021]:
• In the early stages, the API scope is derived from and aligned with client goals
and other requirements, as, for instance, articulated in user stories or job sto-
ries. We briefly summarize the related foundation patterns that are eligible in
this phase.
• Still at an early stage of the API design, endpoints and their operations are
defined on a rather high level of abstraction and elaboration. Our responsibility
patterns come into play in this phase.
• Next, technical details and technology bindings are designed. This is where
our message structure and API quality patterns have their place.
• Finally, the API designs and their implementations are continuously refined
during API evolution. Additional quality patterns can also be applied in this
step, often in the form of API refactoring (to patterns).
The progress with the API design is continuously (and incrementally) documented
throughout the design and evolution steps. Appendix A, “Endpoint Identification
125
126 Part 2 The Patterns
and Pattern Selection Guides” explains how the four ADDR phases and its seven
steps (for instance, “Model API profiles”) and our patterns relate to each other.
The chapter structure of this part comes from these considerations. Each chapter
targets at least one role in our target audience:
Pattern Language
Introduction
In Part 1, we learned that remote APIs have become an important feature of modern
distributed software systems. APIs provide integration interfaces exposing remote
system functionality to end-user applications such as mobile clients, Web applica-
tions, and third-party systems. Not only end-user applications consume and rely on
APIs—distributed backend systems and microservices within those systems require
APIs to be able to work with each other as well.
Lakeside Mutual, a fictitious insurance company, and its microservices-based
applications provided us with an example case. We saw that API design and evo-
lution involve many recurring design issues to resolve conflicting requirements and
find appropriate trade-offs. Decision models for groups of related issues presented
options and criteria to guide us through the required design work. Patterns appeared
as alternative options in these decisions.
This chapter takes the next step. It starts with a pattern language overview and
then proposes navigation paths through the language. It also introduces a first set
of basic scoping and structuring patterns. Having read this chapter, you will be
able to explain the scope of our pattern language (in terms of topics covered and
architectural concerns) and find patterns you are interested in (for instance, by pro-
ject phase). You will also be able to characterize the API under construction by its
visibility and integration type by way of foundation patterns and know about the
basic structure patterns that constitute the syntactic building blocks of request and
response messages (and many of the other patterns in our language).
127
128 Chapter 4 Pattern Language Introduction
Should complex data whose parts have containment or other domain-level rela-
tions be embedded in message representations, or should links be provided to
look up this data with separate calls to other operations in the same (or other)
API endpoints?
Request Message
curl –X GET "http://localhost:8080/customers/rgpp0wkpec" –H "accept */*"
Frontend Backend
Response Message
HTTP 200/OK
{
"_links": [
"deprecation": "string“
"href": "string"
],
"birthday": "1982-02-12T09:10:07.370Z",
"moveHistory": [
{
"city": "Sample City", Decision required about
"postalCode": "aZipCode", moveHistory data:
"streetAddress": "Road 1"
} embed in body payload
] or provide a link to it?
}
Figure 4.1 Exemplary API call: Exchanged messages and their structure
Two of our patterns offer alternative answers to this question: Embedded Entity
(shown in Figure 4.1) and Linked Information Holder. Embedded Entity injects
nested data representations into the payload, whereas a Linked Information
Holder places hyperlinks in the payload. In the latter case, the client has to follow
these hyperlinks to obtain the referenced data in subsequent requests to the endpoint
location found in the links. The chosen combination of these two patterns has a
130 Chapter 4 Pattern Language Introduction
strong impact on the API quality. For instance, message size and number of interac-
tions influence both performance and changeability. Both patterns are valid choices,
depending on network and endpoint capabilities, information needs and data access
profiles of clients, backend location of the source data, and so on. These criteria,
therefore, are pattern selection and adoption forces. We will come back to these pat-
terns and their forces in Chapter 7, “Refine Message Design for Quality.”
• When and Why to Apply establishes the context and preconditions for pattern
eligibility, followed by a problem statement that specifies a design issue to be
resolved. Different forces on the design explain why the problem is hard to
solve. Architectural decision drivers and conflicting quality attributes are often
referenced here; a nonsolution may also be pointed out.
• The How It Works section presents a conceptual, generalized solution to the
design question from the problem statement that describes how the solution
works and which variants (if any) we observed in practice.
• The Example section shows how the solution can be implemented in a concrete
application context, for instance, when working with a particular technology
set such as HTTP and JSON.
• The Discussion section explains to what extent the solution resolves the pat-
tern forces; it may also include additional pros and cons and identify alterna-
tive solutions.
• The Related Patterns section points to the next patterns that become eligible
and interesting once a particular one has been applied.
• Finally, additional pointers and references are given under More Information.
Navigating through the Patterns 131
Coming back to our two exemplary patterns, Linked Information Holder and
Embedded Entity are documented in this format in Chapter 7.
Note that using a pattern does not dictate a particular implementation but leaves
a lot of flexibility for its project-context-specific adoption. In fact, patterns should
never be followed blindly but should be seen as a tool or guide. A product- or project-
specific design can satisfy its concrete, actual requirements only if it knows them
(which is hard for a generalized artifact such as a pattern).
1. This “ask for one, get three” tactic is an exception to our general rule, “if in doubt, leave it out”
[Zimmermann 2021b], fortunately only on the meta-level. Hopefully, standards committees and API
designers stick to this rule better than we do ;-).
132 Chapter 4 Pattern Language Introduction
Evolution Patterns:
«Basic Concept» * Version Identifier
API-Level Patterns: * Semantic Versioning
* API Description API
* Experimental Preview
* Pricing Plan - name: String * Aggressive Obsolescence
* Rate Limit - version: String * Limited Lifetime Guarantee
* Service Level Agreement - description: String * Two in Production
Endpoint Patterns:
* Processing Resource
* Information Holder Resource «Basic Concept» «Basic Concept» Operation-Level Patterns:
* Processing Resource Endpoint Operation * State Creation Operation
* Information Holder Resource * Retrieval Operation
* Operational Data Holder - name: String * State Transition Operation
* Master Data Holder - responsibilityPattern: String * Computation Function
* Reference Data Holder
* Link Lookup Resource
* Data Transfer Resource
0..1
«Basic Concept» «Basic Concept»
Message-Level Patterns
Request Message Payload Response Message Payload
(most impact on request):
* API Key - protocolHeaders: NameAndValueSet - protocolHeaders: NameAndValueSet
* Conditional Request - requestPayload: RepresentationElements - responsePayload: RepresentationElements
* Request Bundle
* Wish List
* Wish Template
Call to action: When being confronted with an API design task, ask yourself
which of these scopes you are about to deal with and refer to Figure 4.2 to find
patterns of interest for this task.
• Responsibility patterns: What is the architectural role played by each API end-
point? What are the operation responsibilities? How do these roles and respon-
sibilities impact service decomposition and API granularity?
• Structure patterns: What is an adequate number of representation elements
for request and response messages? How should these elements be structured?
How can they be grouped and annotated?
• Quality patterns: How can an API provider achieve a certain level of design
time and runtime qualities while using its resources in a cost-effective way?
How can the API quality trade-offs be communicated and accounted for?
• Evolution patterns: How can life-cycle management concerns such as support
periods and versioning be dealt with? How can backward compatibility be
promoted and unavoidable breaking changes be communicated?
Call to action: Think about an API design issue you were confronted with recently.
Does it fit in any of the preceding categories? Do any of the questions and pattern
names suggest that the pattern might be able to resolve the issue? If so, you may
want to go to the respective chapter and pattern right now (and return here later).
If you need more information, you can consult the cheat sheet in Appendix A.
2. https://api-patterns.org
134 Chapter 4 Pattern Language Introduction
4
API Visibility and Integration Types
AP Basic Message Structure
5
Define Endpoint Types
and Operations
6
Design Request and Response
Message Representations Information Processing Data Transfer
Holder Resource Resource
Resource
Data Metadata Id Element Link Element State Creation Retrieval State Transition
Element
Eleme Element Operation Operation Operation
7
Refine Message Design for Quality
v0.1
v1.2 v1.3 v2.1
Pagination ?
Wish List Wish Template
Experimental Aggressive Two in
v1.1
API Service Level Pricing Plan Rate Limit Limited Version Semantic
Description Agreement Lifetime Identifier Versioning
Guarantee
APIs endpoints are identified and characterized by their roles in the overall system/
architecture at the early stages (inception). Next, operations are drafted with their
request and response message structure conceptualized and designed initially (elab-
oration). Quality improvements follow (construction). An approach to versioning
136 Chapter 4 Pattern Language Introduction
and a support/lifetime strategy is specified for APIs when they go live (transition);
updates are possible later on.
While Table 4.1 has an order from top to bottom (as all tables do), it can be
walked through multiple times, even within a single two-week sprint. We do not pro-
pose a waterfall model here; it is perfectly fine to go back and forth, for instance
when applying agile project organization practices. In other words, each sprint may
contain inception, elaboration, construction, and transition tasks (and apply related
patterns).
You might be wondering how the Align-Define-Design-Refine (ADDR) phases
(see introduction to Part 2) relate to the phases in the Unified Process and Table 4.1.
Our take is: Align corresponds to inception, the Define activities happen during
elaboration. Design work stretches from elaboration to construction iterations;
construction and transition (and later evolution and maintenance phases) provide
opportunities to Refine the design continuously.
Call to action: Which phase is your current API design effort in? Do the listed
patterns suggest being eligible for consideration in your design? You may want
to revisit Table 4.1 each time your design reaches a certain milestone or each time
you pick an API-related story from the product backlog at the start of a sprint.
Answering these two questions helps to scope and characterize an API and its
purpose: Frontend Integration and Backend Integration are two types of direc-
tions (or purpose and architectural position) of APIs. Public API, Community API,
and Solution-Internal API define API visibility. Figure 4.4 provides a pattern map
for these five patterns.
codify integration
Frontend Backend aspects of the API
Integration Integration
Pattern:
frontEnd intEgration
How can client-side end-user interfaces that are physically separated from
server-side business logic and data storage be populated and updated with
computing results, result sets from searches in data sources, and detailed
information about data entities? How can application frontends invoke activi-
ties in a backend or upload data to it?
Let the backend of a distributed application expose its services to
one or more application frontends via a message-based remote Frontend
Integration API.
The application frontends serving end users may be internal ones or be part of
external systems. Frontend Integration APIs are consumed by API clients in these
types of application frontends. Figure 4.5 positions the Frontend Integration
pattern in its context.
System A
User Interface
Frontend
API
Integration
Business Logic
Data Persistence
Figure 4.5 FRONTEND INTEGRATION: An API connects a remote user interface with backend
logic and data
Foundations: API Visibility and Integration Types 139
The Business Logic Layer [Fowler 2002] in the backend is a natural entry point.
Sometimes the user interface is also split up between client and server. In such cases,
the API might reside on the user interface level as well.
Details
Decide whether the API is a Public API, a Community API, or a Solution-
Internal API. Compose the request and, optionally, response messages of the API
operations from one or more Atomic Parameters and Parameter Trees (see later
sections for explanations of these patterns).
Realize the selected API endpoint candidates with the help of the role and respon-
sibility patterns (Chapter 5), the message structure patterns (Chapter 6), and the
quality patterns (Chapters 6 and 7). Consciously decide if and how to version the
integration API; consider one or more of our evolution patterns (Chapter 8, “Evolve
APIs”) when doing so. Document the API contract and the terms and conditions of
its use in an API Description and supplemental artifacts (Chapter 9).
A message-based remote Frontend Integration API is often realized as an
HTTP resource API.3 Other remoting technologies, such as gRPC [gRPC], trans-
ferred over HTTP/2 [Belshe 2015], or Web Sockets [Melnikov 2011], can also be used.
GraphQL has become popular recently, promising to avoid under- and overfetching.4
Frontend Integration APIs either have a general purpose that fits all clients or
specialize in providing different “Backends For Frontends” [Newman 2015] per type
of client or user interface technology.
Pattern:
baCkEnd intEgration
3. HTTP resource APIs use the uniform interface of the REST style and invoke HTTP methods such as
POST, GET, PUT, PATCH, and DELETE on URIs. If they adhere to additional constraints of REST,
such as using hyperlinks to transfer state, they may also be called RESTful HTTP APIs.
4. GraphQL can be seen as a large-scale framework realization of our Wish Template pattern from
Chapter 7.
140 Chapter 4 Pattern Language Introduction
How can distributed applications and their parts, which have been built inde-
pendently and are deployed separately, exchange data and trigger mutual
activity while preserving system-internal conceptual integrity without intro-
ducing undesired coupling?
Integrate the backend of a distributed application with one or more other
backends (of the same or other distributed applications) by exposing its ser-
vices via a message-based remote Backend Integration API.
Such Backend Integration APIs are never directly used by frontend clients of
the distributed application but are consumed by other backends exclusively.
Figure 4.6 positions the pattern in the first of its two application contexts, busi-
ness-to-business (or system-to-system) integration.
System A System B
Backend
Integration
Figure 4.7 illustrates the second usage context of the pattern, application-inter-
nal decomposition of business logic into service components exposing a Solution-
Internal API.
The entry to the business logic layer is a suitable location for a Backend Inte-
gration API. Access control, authorization enforcement, system transaction man-
agement, and business rule evaluation typically are already located here. In some
data-centric scenarios not requiring much logic, it may make sense to integrate on
the data persistence layer instead (this is not shown in Figure 4.7).
Foundations: API Visibility and Integration Types 141
Service-Oriented System
Backend
Integration
Data Persistence Data Persistence
Details
Decide on the visibility of the integration API: the options are Public API, Commu-
nity API, and Solution-Internal API. Compose the request and, optionally, response
messages of the API operations from one or more Atomic Parameters, possibly
nested in Parameter Trees (discussed further under “Basic Structure Patterns”).
Define the roles of the API endpoints in the Backend Integration and the responsi-
bilities of their operation (Chapter 5). Design the messages in detail with element
stereotypes and quality improvement patterns (Chapters 6 and 7). Consciously decide
if and how to version the integration API over its lifetime (Chapter 8) when doing so.
Create an API Description and supplemental information (Chapter 9).
Apply a systematic approach to application landscape planning (systems of sys-
tems design). Consider strategic domain-driven design (DDD) [Vernon 2013] as a
light approach to enterprise architecture management (“software city planning”). To
decompose a single system into services, apply cutting criteria derived from func-
tional requirements and domain model [Kapferer 2021, Gysel 2016] and operational
requirements such as scaling needs and developmental concerns such as independent
changeability [Zimmermann 2017]. Also, consider cloud cost and workload patterns
[Fehling 2014].
To promote interoperability, choose a mature remoting technology that supports
standard messaging protocols and established message exchange formats. In addition
to those listed as options to realize Frontend Integration, asynchronous, queue-
based messaging is often used in Backend Integrations (especially those integrating
separate systems); see discussion in Chapter 1 for rationale and examples.
142 Chapter 4 Pattern Language Introduction
Pattern:
PubLiC aPi
APIs exposed to the World Wide Web do not aim to limit their target audience and
accessibility but often control access to them with API Keys.
Mobile App
Third-Party
Systems
Details
Specify the API endpoints, operations, message representations, quality-of-service
guarantees, and life-cycle support model. Continue this integration design by choos-
ing responsibility patterns and choosing one or more evolution patterns (from Chap-
ters 5 and 8). For instance, mark the API as a Processing Resource, introduce
Version Identifiers, and apply Semantic Versioning.
Use API Keys (Chapter 7) or other security means to control access to the API.
Harden the API from a security and reliability perspective, and also invest in the qual-
ity of API Description and support procedures (Chapter 9). From an API economy
point of view, define a Pricing Plan and implement billing/subscription manage-
ment. Consider introducing Rate Limits for free plans. Document API usage terms
and conditions, for instance, in a Service Level Agreement, and let API consumers
Foundations: API Visibility and Integration Types 143
agree to them as a prerequisite to using the API. Cover fair use and indemnification
in these terms and conditions.5 These patterns are covered in Chapter 9.
Pattern:
COMMUNITY API
Some APIs are shared by clients in different organizations and might be deployed in
and accessible via networks available only to community members.
How can the visibility of and the access to an API be restricted to a closed
user group that does not work for a single organizational unit but for mul-
tiple legal entities (such as companies, nonprofit/nongovernment organiza-
tions, and governments)?
Deploy the API and its implementation resources securely in an access-restricted
location so that only the desired user group has access to it—for instance, in an
extranet. Share the API Description only with the restricted target audience.
Figure 4.9 sketches the Community API pattern in its architectural context.
End Users
(Extranet)
Web App
Community
API
Tenant Ops
Mobile App
Business Logic
Database
5. Being legally binding artifacts, terms and conditions documents and Service Level Agreements of Public
APIs should be written or at least reviewed and approved by professionals specializing in legal matters.
144 Chapter 4 Pattern Language Introduction
Details
Specify the API in terms of its endpoints, operations, message representations, qual-
ity of service guarantees, and life-cycle model. Refer to the solution details of Public
API for more comprehensive (equally valid) hints and related patterns.
Harden the API from a security and reliability perspective, and invest in the qual-
ity of API Description and support procedures (including community-managed
member support). Appoint a communitywide API owner and seek shared funding.
This pattern combines elements from its sibling visibility patterns Public API and
Solution-Internal API (and can be seen as a hybrid of these two patterns). For
instance, it may define a community-specific pricing model (in an approach similar
to that for a Public API), but also may consider colocation of API endpoints and
their implementations (as many Solution-Internal APIs do).
Pattern:
soLution-intErnaL aPi
Figure 4.10 sketches two instances of the Solution-Internal API pattern, sup-
porting an application frontend and another backend component, with sample API
clients and backend implementation.
Details
A collection of related Solution-Internal APIs sometimes is referred to as
Platform API. For instance, all Web APIs exposed in a single cloud provider offering
(or collections of such offerings) qualify as platform APIs; examples include APIs in
Amazon Web Services storage offerings and in Cloud Foundry. The same holds for
all Solution-Internal APIs within a software product such as a message-oriented
middleware; the endpoint and management APIs in ActiveMQ and RabbitMQ may
serve as examples of such platform APIs.
Foundations: API Visibility and Integration Types 145
Web App
Solution-Internal Solution-Internal
Frontend API Backend API
Mobile App
Business Logic 2
Database
Note that independent deployability does not have to imply independent deploy-
ment. A modular monolith [Mendonça 2021], for instance, uses plain messages
exchanging data transfer objects via local APIs; such a modular monolith can be
turned into a microservices-based system more easily than an object-oriented
“instance jungle” with tight couplings between the objects at runtime caused by call-
by-reference between remote methods and distributed garbage collection.
Designing and deploying Solution-Internal APIs for Backend Integration
to improve the coupling characteristics of applications and their parts is a complex
undertaking; both the first wave of service-oriented architectures in the 2000s and
the microservices trend that gained momentum since 2014 target this part of the
design space. Many books and articles exist, including some in this series [Vernon
2021]. We come back to the topic in Chapter 5.
rather common visualization of distributed systems (and their layers and tiers) that
places frontends at the top of figures/model diagrams and backends at the bottom; if
several systems are displayed, this is done along the x-axis of the figure. Note that a
left-to-right organization of such figures also is seen frequently.
You might be wondering why we call out the integration type and API visibil-
ity in pattern form; aren’t all these APIs just APIs with endpoints, operations, and
messages? They are. However, practical experience suggests that the business con-
texts and requirements for the two integration types are different; therefore, APIs
serving frontend and backend fulfill other purposes and are designed differently. For
instance, the protocol choice might differ in the two cases: HTTP often is a natural
(or the only) choice in Frontend Integration, while message queuing is attractive
in Backend Integration. The request and response message structures may vary
too in terms of their breadth and depth. An API that does both either makes design
compromises or has to offer optional features, which tends to complicate its usage.
Similar concerns apply to API visibility; for instance, a Public API often has more
advanced security requirements and stability needs than an internal one; the error
reporting has to consider that API clients and providers might not even know each
other (which is less likely for Solution-Internal APIs).
Next, we look at the building blocks of request and response messages, abstract-
ing from the data definition concepts in exchange formats such as JSON.
For instance, these design issues affect the resource URI (including path param-
eters), query, cookie, header parameters, and message content (also called message
body) when HTTP is the message exchange protocol. GET and DELETE requests
usually do not contain bodies, but responses to such requests do. HTTP POSTs,
PUTs, and PATCHes often contain both request and response bodies but may also
define one or more path, query, header, and cookie parameters. In a WSDL/SOAP
context, we can interpret this design issue as how the SOAP message parts should
be organized and which data types should be used to define the corresponding XML
schema elements. gRPC Protocol Buffers and GraphQL provide similar concepts to
specify messages, with similar granularity decisions required.
The four patterns in this section answer the two questions differently. An Atomic
Parameter describes plain data such as texts and numbers, and an Atomic Parame-
ter List groups several such elementary parameters. Parameter Trees provide nest-
ing (of atoms and other trees), and a Parameter Forest groups multiple such tree
parameters at the top level of a message. The pattern map in Figure 4.11 shows these
four patterns with their relations to each other.
Atomic Parameter
can be grouped to
Simple payload
is leaf of Atomic
is node of
Parameter List
is
Consumer node API Provider
of
Complex, nested
payload can be grouped to
Pattern:
atomiC ParamEtEr
Known from programming languages, basic types are the simplest unit of transmis-
sion in message exchanges between API clients and API providers (of all visibilities
and integration types introduced earlier in this section).
Decide whether the atom is single- or set-valued. Describe the meaning of the
transported values, at least informally, including, for instance, a unit of measure.
Consider specifying a value range to constrain the type of the Atomic Parameter.
Make this value-range information explicit—statically in the schema definition lan-
guage for the chosen message exchange format (for example, JSON Schema, Proto-
col Buffers, GraphQL Schema Language, or XML Schema) and/or dynamically in
runtime metadata.
Figure 4.12 visualizes a single-valued string parameter as a single instance of the
pattern appearing in a request message.
Data Transfer
Representation
Parameter
"ABC"
Figure 4.12 ATOMIC PARAMETER pattern: Single scalar (of basic type)
Basic Structure Patterns 149
In the Lakeside Mutual sample case, Atomic Parameters can be found in all API
operations, for instance, those dealing with services concerning customer informa-
tion. The first example is single-valued:
"city":Data<string>
Note that city is not the only Atomic Parameter in the example. The customer
identifier gktlipwhjr in the path of the URI also qualifies as such.
Atomic parameters may come as collections of basic types, which is expressed by
making the atom set-valued *, as shown in the following MDSL example:
"streetAddress":D<string>*
Atomic Parameters appear in all operation definitions and in their schema com-
ponents. Appendix B presents an OpenAPI specification from the Lakeside Mutual
case.
150 Chapter 4 Pattern Language Introduction
Details
Expressive names from the domain that the API belongs to make the API under-
standable for client developers and nontechnical stakeholders. Each atom might have
an exactly-one cardinality but also be optional (zero-or-one cardinality), set-valued
(at-least-one), or both (zero-or-more). Binary data might have to be encoded, for
instance, in Base64 [Josefsson 2006].
Note that the texts and numbers that travel in Atomic Parameters may actually be
structured internally, for instance, if a string has to match a certain regular expression
or is a collection of identically structured entries (such as the lines in the CSV format).
However, this structure is not something the API provider and the API client deal with
during serialization and deserialization. Preparing and processing valid data remains
a responsibility of the application containing the API client and the API implementa-
tion on the provider side. The API Description may define certain value range and
validation rules, but typically, the enforcement of these rules is not part of the interop-
erability contract but is an implementation-level task (as explained earlier). Note that
this “tunneling” approach is sometimes perceived as an antipattern because it bypasses
serialization/deserialization tools and middleware; this approach might appear to be
convenient, but it introduces technical risk and, possibly, security threats.
Atomic Parameters often play certain roles within a request or response mes-
sage. Chapter 6 highlights four such roles in the section on “Element Stereotypes”:
domain Data Element, Metadata Element, Id Element, and Link Element.
Pattern:
atomiC ParamEtEr List
Sometimes, a single Atomic Parameter is not expressive enough. Two or more such
Atomic Parameters might have strong semantic ties, or the content of a request or
response message might need several parts that are worth distinguishing from an API
client, API provider, or intermediary point of view.
The Atomic Parameter List as a whole, but also its elements, can be optional
or set-valued. These properties should be expressed as cardinalities in the API
Description.
Figure 4.13 sketches an application of the pattern in a request message. The data
transfer representation in the figure has three Atomic Parameter entries.
In the Lakeside Mutual case, an Atomic Parameter List may represent customer
addresses (MDSL notation):
{
"street": ["sampleStreetName"],
"postalCode": "42",
"city": "sampleCityName"
}
allows the API client to indicate that it wants the provider to include certain (but not
all) fields in the response:
The client does not identify the individual fields by a key but by position in the
GET request. The provider iterates through the list to decide whether or not to
include a field in the response. This, in fact, is the essence of an API quality pattern
called Wish List (presented in Chapter 7).
Details
Design advice for single Atomic Parameters is applicable here too; for instance, the
parameters should be named in a meaningful and consistent way; the chosen names
should be part of the domain vocabulary. The order of the atoms in the list should be
logical and express the proximity of the elements to improve human readability. The
API Description should provide representative examples for the permitted combi-
nations (instances of valid lists, that is).
Some platforms do not allow the communication participants to send multiple
scalars in a particular message type. For instance, many programming languages
allow only one return value or object in a response message; the default map-
pings from these languages to JSON and XML schema follow this convention (for
example, JAX-RS and JAX-WS in Java). The pattern cannot be used in that case; a
Parameter Tree has the required expressivity.
Pattern:
ParamEtEr trEE
Listing basic representation elements in a flat Atomic Parameter List that by defini-
tion contains only plain Atomic Parameters often is not sufficient, for instance,
when publishing rich domain data such as an order that contains order items or
products that are sold to many customers (that in turn buy many products).
Note that the pattern is defined recursively to yield the desired nested structures.
In HTTP APIs, nested JSON objects provide the tree structure expressed by this pat-
tern; set-valued tree nodes can be represented with JSON arrays containing JSON
objects corresponding to the nodes.
Figure 4.14 illustrates the pattern conceptually.
Figure 4.14 PARAMETER TREE pattern: Two versus one nesting level
In the Lakeside Mutual case, Parameter Trees can be found in several API opera-
tions that deal with customer and contract data. Picking up the example in Figure 4.1
at the beginning of this chapter, an example of a two-level nesting is as follows (note
that the AddressRecord in the example has already been defined as an Atomic
Parameter List above):
{
"customerId": "111",
"addressRecords": [{
"street": "somewhere1",
"postalCode": "42",
"city": "somewhere2"
}],
154 Chapter 4 Pattern Language Introduction
"moveHistory": [{
"from": {
"street": "somewhere3",
"postalCode": "44",
"city": "somewhere4"
},
"to": {
"street": "somewhere1",
"postalCode": "42",
"city": "somewhere2"
},
"when": "2022/01/01"
}]
}
Details
If the structure of the domain model element(s) represented as parameters is hierar-
chical or associative (with 1:1 relations such as customer overview and details or n:m
relations such as customers buying products), then using Parameter Tree is a natu-
ral choice that is beneficial for understandability compared to other options, such as
representing the complex structure in a flattened list. If additional data (such as secu-
rity information) has to be transmitted with the message, the hierarchical nature of a
Parameter Tree can set the additional data structurally apart from the domain
parameters and is thus well suited for this use case (Context Representation,
Chapter 6).
Parameter Trees are more complex to process than atoms, and bandwidth may
be wasted during message transfer if they contain unnecessary elements or an exces-
sive number of nesting levels. But if the structure that needs to be transferred is a deep
hierarchy, they typically are more efficient both in processing and bandwidth use
than sending multiple messages with simpler structures. Parameter Trees introduce
the risk that sometimes unnecessary information and/or more structure(s) informa-
tion is shared between API client and provider, for instance, when the optionality of
information is not defined explicitly. This might not be optimal with regard to for-
mat autonomy as a facet of loose coupling.
Note the recursive definition of the pattern. When applying the pattern, for
instance, when defining a JSON schema for the body of an HTTP POST request,
making use of such recursive definitions might be elegant (and sometimes cannot be
avoided); choices and optionality of nodes give tree construction processors a chance
6. https://microservice-api-patterns.github.io/MDSL-Specification/datacontract
Basic Structure Patterns 155
to terminate. However, even when doing so, such recursive definitions might also
lead to large message payloads that stress tools and runtime serializers such as Jack-
son (or even crash them).
Pattern:
ParamEtEr forEst
Just as Atomic Parameters may form Atomic Parameter Lists, Parameter Trees
can also be assembled into groups. This is useful only at the top level of a request or
response message header or payload.
Request Message
Data Transfer Representation
The Parameter Trees in the forest are accessed by position or name; in contrast to
trees that may contain other trees, Parameter Forests may not contain other forests.
The JSON rendering of this specification looks very similar to that of a tree of
the same structure:
"customers": [{
"customer": {
"customerId": "42",
"addressRecords": [{
"street": "someText",
"zipCode": "42",
"city": "someText"
}],
"moveHistory": []
}}],
"products": [{ "product": "someText" }]
}
However, a Java interface of the service unveils the slight difference in the opera-
tion signature:
Details
This pattern represents the special case of two or more nested top-level parameters
(or message body elements). In most technology mappings of the pattern, it is
semantically equivalent to a Parameter Tree with the forest members as the first
nesting level (see the JSON example presented earlier).
In HTTP resource APIs, the collection of query, path, cookie parameters, and
body jointly can be seen as such a forest (and is one of the reasons we have this
pattern).
Basic Structure Patterns 157
Flat Parameter Trees and Atomic Parameter Lists can be mapped to path
parameters or the query string of a URI, for instance, via “deepObject” serializa-
tion [OpenAPI 2022]. This gets more difficult or might even be impossible for deeply
nested trees; according to the OpenAPI Specification, the “behavior for nested
objects and arrays is undefined.”
All four types of basic structure elements can be used and combined to create
Metadata Elements, Id Elements, and Link Elements as variations of general-
purpose Data Elements (patterns from Chapter 6). Embedded Entities often come
as Parameter Trees, and Linked Information Holders use Atomic Parameter
Lists to define the link target (Chapter 7). A Version Identifier often is an Atomic
Parameter (Chapter 8).
Optionally, data provenance information can be provided in the API Descrip-
tion. Such information might include the entities, people, and processes involved in
producing the representation elements; the data origins; and where the data moves
over time. Note that such information may increase coupling because the message
receiver might start interpreting and depending on it, making the API harder to
change. The element stereotypes in Chapter 6 describe how to add this and other
semantic information to the representation elements: Metadata Element, Id Ele-
ment, and Link Element.
Chapter 3 covers the four basic structure patterns presented in this section with
their problem-solution pairs.
Summary
In this chapter, we established the scope of our pattern language, introduced its
organization, and discussed possible navigation paths. We also introduced five foun-
dation and four basic structure patterns not covered in depth later in the book.
The patterns capture proven solutions to design problems commonly encountered
when specifying, implementing, and maintaining message-based APIs. To ease navi-
gation, the patterns are grouped by life-cycle phase, scope, and category of design
concern. Each pattern in the following chapters is described following a common tem-
plate, progressing from context and problem to solution and example to discussion
and related patterns.
Summary 159
The basic building blocks of our pattern language were introduced in this chap-
ter, starting from Public API for Frontend Integration to Community API and
Solution-Internal API for Frontend Integration and Backend Integration to
flat and nested message structures including Atomic Parameters and Parameter
Trees.
Once it has been decided which type of API to build and where to expose it, end-
points and their operations can be identified. Assigning endpoint roles and opera-
tion responsibilities helps with that, which is the topic of Chapter 5. The message
and data contract design continues in Chapter 6. Linked Information Holder
and Embedded Entity are two more of the 44 patterns in this book. They served as
examples at the start of this chapter, and we return to them in Chapter 7.
This page intentionally left blank
Chapter 5
API design affects not only the structure of request and response messages, which we
covered in Chapter 4, “Pattern Language Introduction.” It is equally—or even
more—important to position the API endpoints and their operations within the
architecture of the distributed system under construction (the terms endpoints and
operations were introduced in the API domain model in Chapter 1, “Application Pro-
gramming Interface (API) Fundamentals”). If positioning is done without careful
thought, in a hurry, or not at all, the resulting API provider implementation is at risk
for being hard to scale and maintain when inconsistencies degrade conceptual integ-
rity; API client developers might find it difficult to learn and utilize the resulting
mishmash APIs.
The architectural patterns in this chapter play a central role in our pattern lan-
guage. Their purpose is to connect high-level endpoint identification activities with
detailed design of operations and message representations. We employ a role- and
responsibility-driven approach for this transition. Knowing about the technical roles
of API endpoints and the state management responsibilities of their operations
allows API designers to justify more detailed decisions later and also helps with run-
time API management (for instance, infrastructure capacity planning).
This chapter corresponds to the Define phase of the Align-Define-Design-Refine
(ADDR) process outlined in the introduction to Part 2 of the book. You do not have
to be familiar with ADDR to be able to apply its patterns.
161
162 Chapter 5 Define Endpoint Types and Operations
activities can ease the recovery from failures but also make it more difficult. For
example, APIs might provide compensating operations that undo work done
by previous calls to the same API; however, a lack of architectural clarity and
request coordination might also lead to inconsistent application state within
API clients and providers.
• Manageability: While one can design for runtime qualities such as performance,
scalability, and availability, only running the system will tell whether API design
and implementation are adequate. Monitoring the API and its exposed services
is instrumental in determining its adequacy and what can be done to resolve mis-
matches between stated requirements and observed performance, scalability, and
availability. Monitoring supports management disciplines such as fault, configu-
ration, accounting, performance, and security management.
• Consistency and atomicity: Business activities should have an all-or-nothing
semantics; once their execution is complete, the API provider finds itself in a
consistent state. However, the execution of the business activity may fail, or
clients may choose to explicitly abort or compensate it (here, compensation
refers to an application-level undo or other follow-up operation that resets the
provider-side application state to a valid state).
• Idempotence: Idempotence is another property that influences or even steers
the API design. An API operation is idempotent if multiple calls to it (with the
same input) return the same output and, for stateful operations, have the same
effect on the API state. Idempotence helps deal with communication errors by
allowing simple message retransmission.
• Auditability: Compliance with the business process model is ensured by audit
checks performed by risk management groups in enterprises. All APIs that
expose functionality that is subject to be audited must support such audits and
implement related controls so that it is possible to monitor business activities
execution with logs that cannot be tampered with. Satisfying audit require-
ments is a design concern but also influences service management at runtime
significantly. The article “Compliance by Design—Bridging the Chasm between
Auditors and IT Architects,” for instance, introduces “Completeness, Accuracy,
Validity, Restricted Access (CAVR)” compliance controls and suggests how to
realize such controls, for instance in service-oriented architectures [Julisch 2011].
in the books that we list in the preface). Here, we present patterns that carve out
important architectural characteristics of API endpoints and operations; doing so
simplifies and streamlines the application of these other tactics and patterns.
Some of the architectural questions an API design has to answer concern the input
to operations:
What can and should the API provider expect from the clients? For instance, what
are its preconditions regarding data validity and integrity? Does an operation
invocation imply state transfer?
What are the operation postconditions? What can the API client in turn expect
from the provider when it sends input that meets the preconditions? Does a
request update the provider state?
In an online shopping example, for instance, the order status might be updated
and can be obtained in subsequent API calls, with the order confirmation containing
all (and only) the purchased products.
Different types of APIs deal with these concerns differently. A key decision is
whether the endpoint should have activity- or data-oriented semantics. Hence, we
introduce two endpoint roles in this chapter. These types of endpoints correspond to
architectural roles as follows:
Data
Transfer
Resource
Processing Information
Resource Holder
Resource
?
Stored data characteristics
Responsibilities & constraints
A A’
(endpoint-level)
Mutable by Client
(operation-level)
no
A A’
Figure 5.1 Pattern map for this chapter (endpoint roles and operations responsibilities)
Endpoint Roles (aka Service Granularity) 167
Endpoint Roles
+ stateCreationOperation() + createInformationHolder()
+ retrievalOperation() + getInformationHolder()
+ stateTransitionOperation() + updateInformationHolder()
+ computationFunction() + deleteInformationHolder()
+ searchInformationHolder()
The two general endpoint roles are Processing Resource and Information
Holder Resource. They may expose different types of operations that write, read,
read-write, or only compute. There are five Information Holder Resource spe-
cializations, answering the following question differently:
How can data-oriented API endpoints be classified by data lifetime, link struc-
ture, and mutability characteristics?
Pattern:
ProCEssing rEsourCE
How can an API provider allow its remote clients to trigger actions in it?
How can clients ask an API endpoint to perform a function that represents a
business capability or a technical utility? How can an API provider expose the
capability of executing a command to its clients that computes some output
from the client’s input and, possibly, from the provider’s own state?
When invoking provider-side processing upon request from remote clients, gen-
eral design concerns are as follows:
also be defined. Not all of these properties have to be disclosed to API clients,
but they still must be described in the provider-internal API documentation.
API designers have to decide how much functionality each API endpoint and
its operations should expose. Many simple interactions give the client a lot of
control and can make the processing highly efficient, but they also introduce
coordination effort and evolution challenges; few rich API capabilities can pro-
mote qualities such as consistency but may not suit each client and therefore
may waste resources. The accuracy of the API Description matters as much as
that of its implementation.
• Learnability and manageability: An excessive number of API endpoints and
operations leads to orientation challenges for client programmers, testers, and
API maintenance and evolution staff (which might or might not include the
original developers); it becomes difficult to find and choose the ones appropri-
ate for a particular use case. The more options available, the more explana-
tions and decision-making support have to be given and maintained over time.
• Semantic interoperability: Syntactic interoperability is a technical concern for
middleware, protocol, and format designers. The communication parties must
also agree on the meaning and impact of the data exchanged before and after
any operation is executed.
• Response time: Having invoked the remote action, the client may block until
a result becomes available. The longer the client has to wait, the higher the
chances that something will break (either on the provider side or in client appli-
cations). The network connection between the client and the API may time out
sooner or later. An end user waiting for slow results may click refresh, thus
putting additional load on an API provider serving the end-user application.
• Security and privacy: If a full audit log of all API invocations and resulting
server-side processing has to be maintained (for instance, because of data
privacy requirements), statelessness on the provider side is an illusion even if
application state is not required from a functional requirement point of view.
Personal sensitive information and/or otherwise classified information (for
example, by governments or enterprises) might be contained in the request and
response message representations. Furthermore, in many scenarios one has to
ensure that only authorized clients can invoke certain actions (that is, com-
mands, conversation parts); for instance, regular employees are usually not
permitted to increase their own salary in the employee management systems
integrated via Community APIs and implemented as microservices. Hence, the
security architecture design has to take the requirements of processing-centric
170 Chapter 5 Define Endpoint Types and Operations
API operations into account—for instance in its policy decision point (PDP)
and policy enforcement point (PEP) design and when deciding between role-
based access control (RBAC) and attribute-based access control (ABAC). The
processing resource is the subject of API security design [Yalon 2019] but also
is an opportunity to place PEPs into the overall control flow. The threat model
and controls created by security consultants, risk managers, and auditors also
must take processing-specific attacks into account, for instance denial-of-
service (DoS) attacks [Julisch 2011].
• Compatibility and evolvability: The provider and the client should agree on
the assumptions concerning the input/output representations as well as the
semantics of the function to be performed. The client expectations should
match what is offered by the provider. The request and response message
structures may change over time. If, for instance, units of measure change or
optional parameters are introduced, the client must have a chance to notice
this and react to it (for instance, by developing an adapter or by evolving itself
into a new version, possibly using a new version of an API operation). Ideally,
new versions are forward and backward compatible with existing API clients.
These concerns conflict with each other. For instance, the richer and the more
expressive a contract is, the more has to be learned, managed, and tested (with regard
to interoperability). Finer-grained services might be easier to protect and evolve, but
there will be many of them, which have to be integrated. This adds performance
overhead and may raise consistency issues [Neri 2020].
A “Shared Database” [Hohpe 2003] that offers actions and commands in the
form of stored procedures could be a valid integration approach (and is used in prac-
tice), but it creates a single point of failure, does not scale with a growing number
of clients, and cannot be deployed or redeployed independently. Shared Databases
containing business logic in stored procedures do not align well with service design
principles such as single responsibility and loose coupling.
How It Works
For the new endpoint, define one or more operations, each of which takes over
a dedicated processing responsibility (“action required”). Computation Function,
State Creation Operation, and State Transition Operation are common in
activity-oriented Processing Resources. Retrieval Operations mostly are lim-
ited to mere status/state checks here and are more commonly found in data-oriented
Information Holder Resources. For each of these operations, define a “Com-
mand Message” for the request. Add a “Document Message” for the response when
realizing an operation as a “Request-Reply” message exchange [Hohpe 2003]. Make
the endpoint remotely accessible for one or more API clients by providing a unique
logical address (for instance, a Uniform Resource Identifier [URI] in HTTP APIs).
Figure 5.3 sketches this endpoint-operation design in a UML class diagram.
Endpoint Roles
API
Processing Resource
+ preconditions
+ invariants
+ postconditions
- resourceState // here: processInstanceState
+ stateCreationOperation(in): ResponseMessage1
+ retrievalOperation(in): ResponseMessage2
+ stateTransitionOperation(in): ResponseMessage3
+ computationFunction(in): ResponseMessage4
Resource State
ProcessingResourceImpl
+ createUpdateDelete(Data)
- applicationState
+ lookupById(key): Value
+ retrieve(query): Set<Data> + processOperation(in): ResponseMessageN
Figure 5.3 PROCESSING RESOURCES represent activity-oriented API designs. Some operations
in the endpoint access and change application state, others do not. Data is exposed only in
request and response messages
172 Chapter 5 Define Endpoint Types and Operations
The request message should make the performed action explicit and allow the API
endpoint to determine which processing logic to execute. These actions might repre-
sent a general-purpose or an application-domain-specific functional system capabil-
ity (implemented within the API provider or residing in some backend and accessed
via an outbound port/adapter) or a technical utility.
The request and response messages possibly can be structured according to any of
the four structural representation patterns Atomic Parameter, Atomic Parameter
List, Parameter Tree, and Parameter Forest. The API Description has to docu-
ment the syntax and semantics of the Processing Resource (including operation
pre- and postconditions as well as invariants).
The Processing Resource can be a “Stateful Component” or a “Stateless Com-
ponent” [Fehling 2014]. If invocations of its operations cause changes in the (shared)
provider-side state, the approach to data management must be designed deliberately;
required decisions include strict vs. weak/eventual consistency, optimistic vs. pes-
simistic locking, and so on. The data management policies should not be exposed
in the API (which would make them visible to the API client), but open and close
(or commit, rollback) system transactions be placed inside the API implementation,
preferably at the operation boundary. Application-level compensating operations
should be offered to handle things that cannot be undone easily by system transac-
tion managers. For instance, an email that is sent in an API implementation cannot
be taken back once it has left the mail server; a second mail, “Please ignore the previ-
ous mail,” has to be sent instead [Zimmermann 2007; Richardson 2018].
Example
The Policy Management backend of the Lakeside Mutual case contains a stateful
Processing Resource InsuranceQuoteRequestCoordinator that offers State
Transition Operations, which move an insurance quotation request through vari-
ous stages. The resource is implemented as an HTTP resource API in Java and Spring
Boot:
@RestController
@RequestMapping("/insurance-quote-requests")
public class InsuranceQuoteRequestCoordinator {
@Operation(
summary = "Updates the status of an existing " +
"Insurance Quote Request")
@PreAuthorize("isAuthenticated()")
@PatchMapping(value = "/{id}")
public ResponseEntity<InsuranceQuoteRequestDto>
respondToInsuranceQuote(
Endpoint Roles (aka Service Granularity) 173
Authentication,
@Parameter(description = "the insurance quote " +
"request's unique id", required = true)
@PathVariable Long id,
@Parameter(description = "the response that " +
"contains the customer's decision whether " +
"to accept or reject an insurance quote",
required = true)
@Valid @RequestBody
InsuranceQuoteResponseDto insuranceQuoteResponseDto) {
@RestController
@RequestMapping("/riskfactor")
public class RiskComputationService {
@Operation(
summary = "Computes the customer's risk factor.")
@PostMapping(
value = "/compute")
public ResponseEntity<RiskFactorResponseDto>
computeRiskFactor(
@Parameter(description = "the request containing " +
"relevant customer attributes (e.g., birthday)",
required = true)
@Valid @RequestBody
RiskFactorRequestDto riskFactorRequest) {
Discussion
Business activity- and process-orientation can reduce coupling and promote infor-
mation hiding. However, instances of this pattern must make sure not to come across
as remote procedure call (RPC) tunneled in a message-based API (and consequently
174 Chapter 5 Define Endpoint Types and Operations
be criticized because RPCs increase coupling, for instance, in the time and format
autonomy dimensions). Many enterprise applications and information systems do
have “business RPC” semantics, as they execute a business command or transaction
from a user that must be triggered, performed, and terminated somehow. According
to the original literature and subsequent collections of design advice [Allamaraju
2010], an HTTP resource does not have to model data (or only data), but can repre-
sent such business transactions, long-running ones in particular.1 Note that “REST
was never about CRUD” [Higginbotham 2018]. The evolution of Processing
Resources is covered in Chapter 8.
A Processing Resource can be identified when applying a service identification
technique such as dynamic process analysis or event storming [Pautasso 2017a];
this has a positive effect on the “business alignment” tenet in service-oriented
architectures. One can define one instance of the pattern per backend integration
need becoming evident in a use case or user story; if a single execute operation is
included in a Processing Resource endpoint, it may accept self-describing action
request messages and return self-contained result documents. All operations in the
API have to be protected as mandated by the security requirements.
In many integration scenarios, activity- and process-orientation would have to be
forced into the design, which makes it hard to explain and maintain (among other
negative consequences). In such cases, Information Holder Resource is a better
choice. It is possible to define API endpoints that are both processing- and data-
oriented (just like many classes in object-oriented programming combine stor-
age and behavior). Even a mere Processing Resource may have to hold state (but
will want to hide its structure from the API clients). Such joint use of Processing
Resource and Information Holder Resource is not recommended for microser-
vices architectures due to the amount of coupling possibly introduced.
Different types of Processing Resources require different message exchange pat-
terns, depending on (1) how long the processing will take and (2) whether the client
must receive the result immediately to be able to continue its processing (otherwise,
the result can be delivered later). Processing time may be difficult to estimate, as it
depends on the complexity of the action to be executed, the amount of data sent
by the client, and the load/resource availability of the provider. The Request-Reply
pattern requires at least two messages that can be exchanged via one network con-
nection, such as one HTTP request-response pair in an HTTP resource API. Alter-
natively, multiple technical connections can be used, for instance, by sending the
command via an HTTP POST and polling for the result via HTTP GET.
1. Note that HTTP is a synchronous protocol as such; hence, asynchrony has to be added on the appli-
cation level (or by using QoS headers or HTTP/2) [Pautasso 2018]. The Data Transfer Resource
pattern describes such design.
Endpoint Roles (aka Service Granularity) 175
Related Patterns
This pattern explains how to emphasize activity; its Information Holder Resource
sibling focuses on data orientation. Processing Resources may contain operations
that differ in the way they deal with provider-side state (stateless services vs. stateful
processors): State Transition Operation, State Creation Operation, Computa-
tion Function, and Retrieval Operation.
Processing Resources are often exposed in Community APIs, but also found
in Solution-Internal APIs. Their operations are often protected with API Keys
and Rate Limits. A Service Level Agreement that accompanies the technical API
contract may govern their usage. To prevent technical parameters from creeping into
the payload in request and response messages, such parameters can be isolated in a
Context Representation.
The three patterns “Command Message,” “Document Message,” and “Request-
Reply” [Hohpe 2003] are used in combination when realizing this pattern. The
“Command” pattern in [Gamma 1995] codifies a processing request and its invoca-
tion data as an object and as a message, respectively. Processing Resource can be
seen as the remote API variant of the “Application Service” pattern in [Alur 2013]. Its
provider-side implementations serve as “Service Activators” [Hohpe 2003].
Other patterns address manageability; see our evolution patterns in Chapter 8,
“Evolve APIs,” for design-time advice and remoting patterns books [Voelter 2004;
Buschmann 2007] for runtime considerations.
More Information
Processing Resources correspond to “Interfacers” that provide and protect access
to service providers in responsibility-driven design (RDD) [Wirfs-Brock 2002].
Chapter 6 in SOA in Practice [Josuttis 2007] is on service classification; it com-
pares several taxonomies, including the one from Enterprise SOA [Krafzig 2004].
Some of the examples in the process services type/category in these SOA books qual-
ify as known uses of this pattern. These two books include project examples and
case studies from domains such as banking and telecommunications.
176 Chapter 5 Define Endpoint Types and Operations
“Understanding RPC vs REST for HTTP APIs” [Sturgeon 2016a] talks about
RPC and REST, but taking a closer look, it actually (also) is about deciding between
Processing Resource and Information Holder Resource.
The action resource topic area/category in the API Stylebook [Lauret 2017] pro-
vides a (meta) known use for this pattern. Its “undo” topic is also related because
undo operations participate in application-level state management.
Pattern:
information HoLdEr rEsourCE
How can domain data be exposed in an API, but its implementation still be
hidden?
More specifically,
How can an API expose data entities so that API clients can access and/or mod-
ify these entities concurrently without compromising data integrity and quality?
One could think of hiding all data structures behind processing-oriented API oper-
ations and data transfer objects (DTOs) analogous to object-oriented programming
178 Chapter 5 Define Endpoint Types and Operations
(that is, local object-oriented APIs expose access methods and facades while keep-
ing all individual data members private). Such an approach is feasible and promotes
information hiding; however, it may limit the opportunities to deploy, scale, and
replace remote components independently of each other because either many fine-
grained, chatty API operations are required or data has to be stored redundantly. It
also introduces an undesired extra level of indirection, for instance, when building
data-intensive applications and integration solutions.
Another possibility would be to give direct access to the database so that consum-
ers can see for themselves what data is available and directly read and even write it if
allowed. The API in this case becomes a tunnel to the database, where consumers can
send arbitrary queries and transactions through it; databases such as CouchDB pro-
vide such data-level APIs out-of-the-box. This solution completely removes the need
to design and implement an API because the internal representation of the data is
directly exposed to clients. Breaking basic information-hiding principles, however, it
also results in a tightly coupled architecture where it will be impossible to ever touch
the database schema without affecting every API client. Direct database access also
introduces security threats.
How It Works
Make the endpoint remotely accessible for one or more API clients by providing a
unique logical address. Let each operation of the Information Holder Resource
have one and only one of the four operation responsibilities (covered in depth in
the next section): State Creation Operations create the entity that is represented
by the Information Holder Resource. Retrieval Operations access and read
an entity but do not update it. They may search for and return collections of such
entities, possibly filtered. State Transition Operations access existing entities and
update them fully or partially; they may also delete them.
For each operation, design the request and, if needed, response message struc-
tures. For instance, represent entity relationships as Link Elements. If basic
reference data such as country codes or currency codes are looked up, the response
message typically is an Atomic Parameter; if a rich, structured domain model entity
Endpoint Roles (aka Service Granularity) 179
is looked up, the response is more likely to contain a Parameter Tree that represents
the data transfer representation (a term from the API domain model introduced in
Chapter 1) of the looked-up information. Figure 5.4 sketches this solution.
Endpoint Roles
API
Figure 5.4 INFORMATION HOLDER RESOURCES model and expose general data-oriented
API designs. This endpoint role groups information-access-oriented responsibilities. Its
operations create, read, update, or delete the data held. Searching for data sets is also
supported
Five patterns in our language refine this general solution to data-oriented API
endpoint modeling: Operational Data Holder, Master Data Holder, Refer-
ence Data Holder, Data Transfer Resource, and Link Lookup Resource.
Example
The Customer Core microservice in the Lakeside Mutual sample exposes master
data. The semantics and its operations (for example, changeAddress(...)) of
this service are data- rather than action-oriented (the service is consumed by other
microservices that realize the Processing Resource pattern). Hence, it exposes a
CustomerInformationHolder endpoint, realized as an HTTP resource:
@RestController
@RequestMapping("/customers")
public class CustomerInformationHolder {
@Operation(
summary = "Change a customer's address.")
@PutMapping(
value = "/{customerId}/address")
public ResponseEntity<AddressDto> changeAddress(
@Parameter(
description = "the customer's unique id",
required = true)
@PathVariable CustomerId,
@Parameter(
description = "the customer's new address",
required = true)
@Valid @RequestBody AddressDto requestDto) {
[...]
}
@Operation(
summary = "Get a specific set of customers.")
@GetMapping(
value = "/{ids}")
public ResponseEntity<CustomersResponseDto>
getCustomer(
@Parameter(description =
"a comma-separated list of customer ids",
required = true)
@PathVariable String ids,
@Parameter(description =
"a comma-separated list of the fields" +
Endpoint Roles (aka Service Granularity) 181
Discussion
Information Holder Resources resolve their design forces as follows:
2. One of the classic cognitive biases is that every construction problem looks like a nail if you know
how to use a hammer (and have one at hand). Analysis and design methods are tools made for specific
purposes.
182 Chapter 5 Define Endpoint Types and Operations
• Security: Not all API clients may be authorized to access each Information
Holder Resource in the same way. API Keys, client authentication, and
ABAC/RBAC help protect each Information Holder Resource.
• Data freshness versus consistency: Data consistency has to be preserved for
concurrent access of multiple consumers. Likewise, clients must deal with the
consequences of temporary outages, for instance, by introducing an appro-
priate caching and offline data replication and synchronization strategy. In
practice, the decision between availability and consistency is not as binary and
strict as the CAP theorem suggests, which is discussed by its original authors in
a 12-year retrospective and outlook [Brewer 2012].
If several fine-grained Information Holders appear in an API, many calls to
operations might be required to realize a user story, and data quality is hard to
ensure (because it becomes a shared, distributed responsibility). Consider hid-
ing several of them behind any type of Processing Resource.
• Compliance with architectural design principles: The introduction of Infor-
mation Holder Resource endpoints may break higher-order principles such
as strict logical layering that forbids direct access to data entities from the pres-
entation layer. It might be necessary to refactor the architecture [Zimmermann
2015]—or grant an explicit exception to the rule.
Related Patterns
“Information Holder” is a role stereotype in RDD [Wirfs-Brock 2002]. This general
Information Holder Resource pattern has several refinements that differ with
Endpoint Roles (aka Service Granularity) 183
More Information
Chapter 8 in Process-Driven SOA is devoted to business object integration and deal-
ing with data [Hentrich 2011]. “Data on the Outside versus Data on the Inside” by
Pat Helland explains the differences between data management on the API and the
API implementation level [Helland 2005].
“Understanding RPC vs REST for HTTP APIs” [Sturgeon 2016a] covers the dif-
ferences between Information Holder Resources and Processing Resources in
the context of an RPC and REST comparison.
Various consistency management patterns exist. “Eventually Consistent” by Wer-
ner Vogels, the Amazon Web Services CTO, addresses this topic [Vogels 2009].
Pattern:
oPErationaL data HoLdEr
The data specification unveils that the entity lifetimes and/or update cycles dif-
fer significantly (for instance, from seconds, minutes, and hours to months, years,
and decades) and that the frequently changing entities participate in relationships
with slower-changing ones. For instance, fast-changing data may act mostly as link
sources, while slow-changing data appears mostly as link targets.3
How can an API support clients that want to create, read, update, and/or
delete instances of domain entities that represent operational data that is
rather short-lived, changes often during daily business operations, and has
many outgoing relations?
Several desired qualities are worth calling out, in addition to those applying to
any kind of Information Holder Resource.
• Processing speed for content read and update operations: Depending on the
business context, API services dealing with operational data must be fast, with
low response time for both reading and updating its current state.
• Business agility and schema update flexibility: Depending on the business
context (for example, when performing A/B testing with parts of the live users),
API endpoints dealing with operational data must also be easy to change, espe-
cially when the data definition or schema evolves.
• Conceptual integrity and consistency of relationships: The created and
modified operational data must meet high accuracy and quality standards
if it is business-critical. For instance, system and process assurance audits
inspect financially relevant business objects such as invoices and payments in
enterprise applications [Julisch 2011]. Operational data might be owned, con-
trolled, and managed by external parties such as payment providers; it might
have many outgoing relations to similar data and longer-lived, less frequently
changing master data. Clients expect that the referred entities will be correctly
accessible after the interaction with an operational data resource has success-
fully completed.
3. The context of this pattern is similar to that of its sibling pattern Master Data Holder. It acknowl-
edges and points out that the lifetimes and relationship structure of these two types of data differ (in
German: Stammdaten vs. Bewegungsdaten; see [Ferstl 2006; White 2006]).
Endpoint Roles (aka Service Granularity) 185
One could think of treating all data equally to promote solution simplicity, irre-
spective of its lifetime and relationship characteristics. However, such a unified
approach might yield only a mediocre compromise that meets all of the preced-
ing needs somehow but does not excel with regard to any of them. If, for instance,
operational data is treated as master data, one might end up with an overengineered
API with regard to consistency and reference management that also leaves room for
improvement with regard to processing speed and change management.
How It Works
+ preconditions
+ invariants
+ postconditions
+ create(EntityValues): Entity
+ read(SelectionCriteria): Set<Entity>
+ update(ID, EntityValues): Entity
+ delete(ID): Status
+ archive(Collection<ID>): Collection<Status>
+ listOutgoingReferences(): Set<InformationHolderLinkElement>
Local State
System of System of
Engagement Record
Figure 5.5 OPERATIONAL DATA HOLDER: Operational data has a short to medium lifetime
and may change a lot during daily business. It may reference master data and other
operational data
Operational Data Holders are good candidates for event sourcing [Stettler
2019] whereby all state changes are logged, making it possible for API clients
to access the entire history of state changes for the specific Operational Data
Holder. This may increase the API complexity, as consumers may want to refer
to or retrieve arbitrary snapshots from the past as opposed to simply querying the
latest state.
Example
In an online shop, purchase orders and order items qualify as operational data; the
ordered products and the customers placing an order meet the characteristics of
master data. Hence, these domain concepts are typically modeled as different
“Bounded Context” instances (in DDD) and exposed as separate services, as shown
in Figure 5.6.
0..* 1..*
1 1
Figure 5.6 Online shop example: OPERATIONAL DATA HOLDER (Purchase Order) and
MASTER DATA HOLDERS (Customer, Product) and their relations
Lakeside Mutual, our sample application from the insurance domain, manages
operational data such as claims and risk assessments that are exposed as Web ser-
vices and REST resources (see Figure 5.7).
188 Chapter 5 Define Endpoint Types and Operations
«OperationalDataHolder» «Aggregate»
Offer Remote Facade Offer Aggregate
«MasterDataHolder,OperationalDataHolder» «Aggregate»
Contract Management Remote Facade Contract
Aggregate
«MasterDataHolder» «Aggregate»
Customer Remote Facade Customer
Aggregate
Figure 5.7 Examples of combining OPERATIONAL DATA HOLDER and MASTER DATA
HOLDER: Offers reference contracts and customers, contracts reference customers. In this
example, the remote facades access multiple aggregates isolated from each other. The logical
layer names come from [Evans 2003] and [Fowler 2002]
Discussion
The pattern primarily serves as a “marker pattern” in API documentation, helping to
make technical interfaces “business-aligned,” which is one of the SOA principles and
microservices tenets [Zimmermann 2017].
Sometimes even operational data is kept for a long time: in a world of big data
analytics and business intelligence insights, operational data is often archived for
analytical processing, such as in data marts, data warehouses, or semantic data lakes.
The fewer inbound dependencies an Operational Data Holder has, the easier
to update it is. A limited lifetime of data and data definitions makes API evolution
less challenging; for instance, backward compatibility and integrity management
become less of an issue. It might even be possible to rewrite Operational Data
Holders rather than maintain older versions of them [Pautasso 2017a]. Relax-
ing their consistency properties from strict to eventual [Fehling 2014] can improve
availability.
The consistency and availability management of Operational Data Holders
may prioritize the conflicting requirements differently than Master Data Holders
(depending on the domain and scenario). Business agility, schema update flexibility,
and processing speed are determined by the API implementation.
Endpoint Roles (aka Service Granularity) 189
The distinction between master data and operational data is somewhat subjective
and dependent on application context; data that is needed only temporarily in one
application might be a core asset in another one. For instance, think about purchases
in an online shop. While the shopper cares about the order only until it is delivered
and paid for (unless there is a warranty case or the customer wants to return the
good or repeat the same order in the future), the shop provider will probably keep all
details forever to be able to analyze buying behavior over time (customer profiling,
product recommendations, and targeted advertisement).
The Operational Data Holder pattern can help to satisfy regulatory require-
ments expressed as compliance controls. An example of such requirement and com-
pliance control is “all purchase orders reference a customer that actually exists in a
system of record and in the real world.” Enforcing this rule prevents (or finds) cases
of fraud [Julisch 2011].
Related Patterns
Longer-living information holders with many incoming references are described by
the patterns Master Data Holder (mutable) and Reference Data Holder (immu-
table via the API). An alternative, less data- and more action-oriented pattern is Pro-
cessing Resource. All operation responsibilities patterns, including State Creation
Operation and State Transition Operation, can be used in Operational Data
Holder endpoints.
Patterns from Chapters 4, 6, and 7 are applied when designing the request and
response messages of the operations of the Operational Data Holder. Their suit-
ability heavily depends on the actual data semantics. For instance, entering items into
a shopping basket might expect a Parameter Tree and return a simple success flag
as an Atomic Parameter. The checkout activity then might require multiple com-
plex parameters (Parameter Forest) and return the order number and the expected
delivery date in an Atomic Parameter List. The deletion of operational data can be
triggered by sending a single Id Element and might return a simple success flag and/
or Error Report representation. Pagination slices responses to requests for large
amounts of operational data.
The “Data Type Channel” pattern in [Hohpe 2003] describes how to organize a
messaging system by message semantics and syntax (such as query, price quote, or
purchase order).
Operational Data Holders referencing other Operational Data Holders
may choose to include this data in the form of an Embedded Entity. By contrast,
references to Master Data Holders often are not included/embedded but external-
ized via Linked Information Holder references.
190 Chapter 5 Define Endpoint Types and Operations
More Information
The notion of operational (or transactional) data has its roots in the database and
information integration community and in business informatics (Wirtschaftsinfor-
matik) [Ferstl 2006].
Pattern:
mastEr data HoLdEr
How can I design an API that provides access to master data that lives for a long
time, does not change frequently, and will be referenced from many clients?
In many application scenarios, data that is referenced in multiple places and lives
long has high data quality and data protection needs.
• Master data quality: Master data should be accurate because it is used directly,
indirectly, and/or implicitly in many places, from daily business to strategic
decision making. If it is not stored and managed in a single place, uncoordi-
nated updates, software bugs, and other unforeseen circumstances may lead
to inconsistencies and other quality issues that are hard to detect. If it is stored
centrally, access to it might be slow due to overhead caused by access conten-
tion and backend communication.
• Master data protection: Irrespective of its storage and management policy,
master data must be well protected with suitable access controls and auditing
4. The context of this pattern is similar to that of its alternative pattern Operational Data Holder. It
emphasizes that the lifetimes and relationship structure of these two types of data differ. Here we are
interested in master data, often contrasted with operational data, also called transactional data (in
German, Stammdaten vs. Bewegungsdaten; see Ferstl [2006], White [2006]).
Endpoint Roles (aka Service Granularity) 191
Data ownership and audit procedures differ from those of other types of data.
Master data collections are assets with a monetary value appearing in the balance
sheets of enterprises. Therefore, their definitions and interfaces often are hard to
influence and change; due to external influences on its life cycle, master data may
evolve at a different speed than operational data that references it.
One could think of treating all entities/resources equally to promote solution
simplicity, irrespective of their lifetime and relationship patterns. However, such an
approach runs the risk of not satisfactorily addressing the concerns of stakeholders,
such as security auditors, data owners, and data stewards. Hosting providers and,
last but not least, the real-world correspondents of the data (for instance, customers
and internal system users) are other key stakeholders of master data whose interests
might not be fulfilled satisfactorily by such an approach.
How It Works
Optionally, offer other life-cycle events or state transitions in this Master Data
Holder endpoint. Also optionally, expose additional operations to give the Master
Data Holder domain-specific responsibilities. For instance, an archive might offer
time-oriented retrieval, bulk creations, and purge operations.
192 Chapter 5 Define Endpoint Types and Operations
Master Data
Master Data Holder Management
+ preconditions System
+ invariants
+ postconditions
+ create(EntityValues): Entity
+ read(SelectionCriteria): Set<Entity> System of
+ update(ID, EntityValues): Status Record
+ delete(ID): Status
+ archive(Collection<ID>): Collection<Status>
+ listIncomingReferences(): Set<InformationHolderLinkElement>
+ listOutgoingReferences(): Set<MasterDataHolderLinkElement>
+ validate(): Status
Figure 5.8 MASTER DATA HOLDER. Master data lives long and is frequently referenced by
other master data and by operational data. It therefore faces specific quality and consistency
requirements
The request and response messages of Master Data Holders often take the form
of Parameter Trees. However, more atomic types of request and response message
structure can also be found in practice. Master data creation operations typically
receive a simple to medium complex Parameter Tree because master data might
be complex but is often created in one go, for instance, when being entered com-
pletely by a user in a form (such as an account creation form). They usually return an
Atomic Parameter or an Atomic Parameter List to report the Id Element or Link
Element that identifies the master data entity uniquely/globally and reports whether
or not the creation request was successful (for instance, using the Error Report
pattern). Reasons for failure can be duplicate keys, violations of business rules and
other invariants, or internal server-side processing errors (for instance, temporary
unavailability of backend systems).
Endpoint Roles (aka Service Granularity) 193
the mentioned qualities. In DDD terms, we aim for a rich and deep domain model,
as opposed to an anemic domain model [Fowler 2003]; this should be reflected in the
API design. In many scenarios, it makes sense to identify and call out master data (as
well as operational data) in the domain models so that later design decisions can use
this information.
Example
Lakeside Mutual, our sample application from the insurance domain, features mas-
ter data such as customers and contracts that are exposed as Web services and REST
resources, thus applying the Master Data Holder pattern. Figure 5.9 illustrates
two of these resources as remote facades.
«OperationalDataHolder»
OfferRemoteFacade «ReferenceDataHolder»
CityReferenceDataHolder
«RetrievalOperation»
+ lookupCustomerByName(String) + getCitiesForPostalCode(String): List<String>
«StateCreationOperation»
+ processOfferPlacedEvent()
«MasterDataHolder»
ContractManagementRemoteFacade
«StateTransitionOperation»
+ checkOffer(...)
+ acceptOffer(...)
+ rejectOffer(...)
«StateCreationOperation»
+ processCustomerUpdatedEvent(...)
«MasterDataHolder»
CustomerRemoteFacade
ContractAggregate
«RetrievalOperation»
+ lookupBySearchCriteria(...)
+ getDetails(ID)
«StateCreationOperation»
+ emitCustomerUpdatedEvent(...)
Customer
Aggregate
Figure 5.9 Example of OPERATIONAL DATA HOLDER and MASTER DATA HOLDER interplay.
Operational data references master data, but not vice versa. An application of the REFERENCE
DATA HOLDER pattern is also shown
Endpoint Roles (aka Service Granularity) 195
In this example, the remote facades (offer, contract, customer) access each other
and two domain-layer aggregates in the API implementation.
Discussion
Tagging an API endpoint as a Master Data Holder can help achieve the required
focus on data quality and data protection.
Master data by definition has many inbound dependencies and might also have
outbound ones. Since such data is often under external control, tagging an API end-
point as Master Data Holder also helps to control and limit where such external
dependency is introduced. This way, there will be only one API providing fresh access
to a specific master data source in a consistent way.
Master data often is a valuable company asset that is key to success in the market
(it might even turn a company into an acquisition target). Hence, when exposed as
part of the API, it is particularly important to plan its future evolution in a roadmap
that respects backward compatibility, considers digital preservation, and protects the
data from theft and tampering.
Related Patterns
The Master Data Holder pattern has two alternatives: Reference Data Holder
(with data that is immutable via the API) and Operational Data Holder (exposing
shorter-lived data with less incoming references).
More Information
The notion of master data versus operational data comes from literature in the data-
base community (more specifically, information integration) and in business infor-
matics (Wirtschaftsinformatik in German) [Ferstl 2006]. It plays an important role in
online analytical processing (OLAP), data warehouses, and business intelligence (BI)
efforts [Kimball 2002].
Pattern:
rEfErEnCE data HoLdEr
zip codes, geolocations, currency codes, and units of measurement. Reference data
often is represented by enumerations of string literals or numeric value ranges.
The data transfer representations in the request and response messages of API
operations may either contain or point at reference data to satisfy the information
needs of a message receiver.
How should data that is referenced in many places, lives long, and is immutable
for clients be treated in API endpoints?
How can such reference data be used in requests to and responses from
Processing Resources or Information Holder Resources?
Two desired qualities are worth calling out (in addition to those applying to any
kind of Information Holder Resource).
• Do not repeat yourself (DRY): Because reference data rarely changes (if ever),
there is a temptation to simply hardcode it within the API clients or, if using
a cache, retrieve it once and then store a local copy forever. Such designs work
well in the short run and might not cause any immanent problems—until the
data and its definitions have to change.5 Because the DRY principle is violated,
the change will impact every client, and if clients are out of reach, it may not be
possible to update them.
• Performance versus consistency trade-off for read access: Because reference
data rarely changes (if at all), it may pay off to introduce a cache to reduce
round-trip access response time and reduce traffic if it is referenced and read a
lot. Such replication tactics have to be designed carefully so that they function
as desired and do not make the end-to-end system overly complex and hard to
maintain. For instance, caches should not grow too big, and replication has
to be able to tolerate network partitions (outages). If the reference data does
change (on schema or on content level), updates have to be applied consist-
ently. Two examples are new zip codes introduced in a country and the transi-
tion from local currencies to the Euro (EUR) in many European countries.
5. For instance, it was sufficient to use two digits for calendar years through 1999.
Endpoint Roles (aka Service Granularity) 197
One could treat static and immutable reference data just like dynamic data that is
both read and written. This works fine in many scenarios but misses opportunities
to optimize the read access, for instance, via data replication in content delivery net-
works (CDNs) and might lead to unnecessary duplication of storing and computing
efforts.
How It Works
API
Content
Delivery Network
+ populate(RefDataSet): Status
+ lookup(RefDataKey): RefDataInstance
Backend Systems
+ lookupById(): StaticDataHolder
Figure 5.10 REFERENCE DATA HOLDER. Reference data lives long but cannot be changed via
the API. It is referenced often and in many places
Reference data lives long but hardly ever changes; it is referenced often and in
many places. Hence, the operations of Reference Data Holders may offer direct
access to a reference data table. Such lookups can map a short identifier (such as
a provider-internal surrogate key) to a more expressive, human-readable identifier
and/or entire data set.
The pattern does not prescribe any type of implementation; for instance, a rela-
tional database might come across as an overengineered solution when managing a
list of currencies; a file-based key-value store or indexed sequential access method
(ISAM) files might be sufficient. Key-value stores such as a Redis or a document-
oriented NoSQL database such as CouchDB or MongoDB may also be considered.
Example
Figure 5.11 shows an instance of the pattern that allows API clients to look up zip
codes based on addresses, or vice versa.
Endpoint Roles (aka Service Granularity) 199
OperationalAPI
AddressManagementUtility Admin
Application
+ lookupZIPCode(String, String): String
Discussion
The most common usage scenario for this pattern is the lookup of simple text data
whose value ranges meet certain constraints (for example, country codes, currency
codes, or tax rates).
Explicit Reference Data Holders avoid unnecessary repetition. The purpose
of a Reference Data Holder is to give a central point of reference for helping dis-
seminate the data while keeping control over it. Read performance can be optimized;
immutable data can be replicated rather easily (no risk of inconsistencies as long as
it never changes).
Dedicated Reference Data Holders have to be developed, documented, man-
aged, and maintained. This effort will still be less than that required to upgrade all
clients if such reference data gets hardcoded in them.
Related Patterns
The Master Data Holder pattern is an alternative to Reference Data Holder. It
also represents long-living data, which still is mutable. Operational Data Holders
represent more ephemeral data.
The section “Message Granularity” in Chapter 7, “Refine Message Design for
Quality,” features two related patterns, Embedded Entity and Linked Information
Holder. Simple static data is often embedded (which eliminates the need for a dedi-
cated Reference Data Holder) but can also be linked (with the link pointing at a
Reference Data Holder).
More Information
“Data on the Outside versus Data on the Inside” introduces reference data in the
broad sense of the word [Helland 2005]. Wikipedia provides links to inventories/
directories of reference data [Wikipedia 2022b].
Pattern:
Link LookuP rEsourCE
How can message representations refer to other, possibly many and frequently
changing, API endpoints and operations without binding the message recipi-
ent to the actual addresses of these endpoints?
Endpoint Roles (aka Service Granularity) 201
• API providers want to be able to change the destinations of links freely when
evolving their APIs while workload grows and requirements change.
• API clients do not want to have to change code and configuration (for example,
application startup procedures) when the naming and structuring conventions
for links change on the provider side.
• Coupling between clients and endpoints: If clients use the address of an end-
point to reference it directly, a tight link is created between these parties. The
client references can break for many reasons, such as if the endpoint address
changes or the endpoint is down temporarily.
• Dynamic endpoint references: API designs often bind references to endpoints
at design or deployment time, for instance, hardcoding references in the cli-
ents (while more sophisticated binding schemes exist as well). Sometimes this
is not flexible enough; dynamic changes to endpoint references at runtime are
required. Two examples are endpoints that are taken offline for maintenance
and load balancers working with a dynamic number of endpoints. Another
usage scenario involves intermediaries and redirecting helpers that help over-
come formatting differences after new API versions have been introduced.
• Centralization versus decentralization: Providing exactly one Informa-
tion Holder Resource per data element in the Published Language that is
referenced in requests and responses to other API endpoints via hardcoded
addresses leads to highly decentralized solutions. Other API designs could cen-
tralize the registration and binding of endpoint addresses instead. Any cen-
tralized solution is likely to receive more traffic than a partially autonomous,
distributed one; decentralized ones are easy to build but might become hard to
maintain and evolve.
• Message sizes, number of calls, resource use: An alternative solution to con-
sider for any form of references used in clients is to avoid them, following the
Embedded Entity pattern. However, this increases message sizes. Any solu-
tions for managing references to endpoints in clients generally cause additional
API calls. All these considerations influence the resource use in terms of pro-
vider-side processing resources and network bandwidth.
202 Chapter 5 Define Endpoint Types and Operations
• Dealing with broken links: Clients following references will assume these ref-
erences point at the right existing API endpoints. If such references no longer
work because an API endpoint has been moved, existing clients that do not
know about this may fail (as they are no longer able to connect to the API) or,
even worse, run the risk of receiving out-of-date information from a previous
endpoint version.
• Number of endpoints and API complexity: The coupling problem could be
avoided by having a specific endpoint only for getting the address of another
endpoint. But in the extreme case that all endpoints require such functional-
ity, this tactic would double the number of endpoints, which would make API
maintenance more difficult and increase the API complexity.
A simple approach could be to add lookup operations, which are special types
of Retrieval Operations that return Link Elements to already existing
endpoints. This solution is workable but compromises cohesion within the
endpoints.
How It Works
+ populate(...): Status
+ lookup(...): ResponseMessage
expects delivers
Figure 5.12 A LINK LOOKUP RESOURCE is an API endpoint that merely holds information
about other ones
The link information may come in different forms. Many notations have been
proposed to represent hyperlinks in messages, including JSON-LD [W3C 2019],
HAL [Kelly 2016], WS-Addressing (XML) [W3C 2004].
Variant When the Link Elements point at Processing Resources rather than
Information Holder Resources, a variant of this pattern is constituted: Hyper-
text as the Engine of Application State (HATEOAS) is one of the defining charac-
teristics of truly RESTful Web APIs, according to the definitions of the REST style
[Webber 2010; Erl 2013]. Note that the links in HATEOAS are also referred to as
hypermedia controls.
The addresses of a few root endpoints (also called home resources) are published
(that is, communicated to prospective API clients); the addresses of related services
can then be found in each response. The clients parse the responses to discover the
URIs of resources to be called subsequently. If a Processing Resource is referenced
this way, the control flow and application state management become dynamic and
highly decentralized; the operation-level pattern State Transition Operation
204 Chapter 5 Define Endpoint Types and Operations
Example
In the Lakeside Mutual sample case, two operations to find Information Holder
Resources that represent customers can be specified as follows (notation: MDSL,
introduced in Appendix C):
operation lookupInformationHolderByCriteria
expecting payload {
"filter": P // placeholder parameter P
}
delivering payload {
<<Link_Element>> "uri": URI* // 0..m cardinality
}
Discussion
A centralized Link Lookup Resource providing dynamic endpoint references
decouples clients and providers in terms of location autonomy. The pattern pro-
motes high cohesion within one endpoint, as the lookup responsibility is separated
from the actual processing and information retrieval. As a negative consequence, a
Link Lookup Resource causes extra calls and increases the number of endpoints.
The pattern increases operational costs; the lookup resource must be kept current.
Use of the pattern improves cohesion within endpoints (at the expense of adding
additional, specialized ones).
The pattern has a negative impact on the number of calls clients are required
to send unless caching is introduced to mitigate this effect and lookup calls are
Endpoint Roles (aka Service Granularity) 205
performed only after detecting broken links. The pattern can improve performance
only if the overhead for looking up the Information Holder Resource (or other
provider-internal data storage) over an API operation boundary (so making two calls)
does not exceed the savings achieved by leaner message payloads (of each operation).
If the combination of a Linked Information Holder with a Link Lookup
Resource turns out to add more overhead than performance and flexibility gains,
the Linked Information Holder can be changed to contain a direct link. If the
direct linking still leads to overly chatty message exchanges (conversations) between
API clients and API providers, the referenced data could be flattened as an instance
of Embedded Entity.
The added indirection can help to change the system runtime environment
more freely. Systems that include direct URIs might be harder to change as server
names change. The REST principle of HATEOAS solves this problem for the actual
resource names; only hardcoded client-side links are problematic (unless HTTP
redirections are introduced). Microservices middleware such as API gateways can be
used as well; however, such usage adds complexity to the overall architecture as well
as additional runtime dependencies. Using hypermedia to advance the application
state is one of the defining constraints of the REST style. One has to decide whether
the hypermedia should refer to the resources responsible for provider-side processing
(of any endpoint type) directly or whether a level of indirection should be introduced
to further decouple clients and endpoints (this pattern).
Related Patterns
Instances of this pattern can return links to any of the endpoint types/roles, often to
Information Holder Resources. The pattern uses Retrieval Operations. For
instance, Retrieval Operation instances may return Id Elements pointing at
Information Holder Resources indirectly (that in turn return the data); the Link
Lookup Resource turns the Id Element into a Link Element.
Infrastructure-level service discovery can be used alternatively. For instance, pat-
terns such as “Service Registry,” “Client-Side Discovery,” and “Self Registration”
have been captured by [Richardson 2018].
This pattern is an API-specific version/refinement of the more general “Lookup”
pattern described in [Kircher 2004] and [Voelter 2004]. At a more abstract level, the
pattern also is a specialization of the Repository pattern described in [Evans 2003],
effectively acting as a meta-repository.
More Information
SOA books cover related concepts such as service repositories and registries. In RDD
terms, a Link Lookup Resource acts as a “Structurer” [Wirfs-Brock 2002].
206 Chapter 5 Define Endpoint Types and Operations
If multiple results of the same type are returned, the Link Lookup Resource turns
into a “Collection Resource.” Collection Resources can be seen as a RESTful HTTP
pendant of this pattern, adding add and remove support. Recipe 2.3 in the RESTful
Web Services Cookbook [Allamaraju 2010] features them; Chapter 14 of that book
discusses discovery. Collections use links to enumerate their content and allow clients
to retrieve, update, or delete individual items. As shown in [Serbout 2021], APIs can
feature read-only collections, appendable collections, as well as mutable collections.
Pattern:
data transfEr rEsourCE
exchange that are hidden behind a Network Address Translation (NAT) table
or a firewall.
• Communication constraints: Some communication participants may be una-
ble to talk to each other directly. For instance, clients in the client/server archi-
tectural style by definition are not capable of accepting incoming connections.
Also, some communication participants may not be allowed to install any soft-
ware required for communication beyond a basic HTTP client library locally
(for example, a messaging middleware). In such cases, indirect communication
is the only possibility.
• Reliability: Networks cannot be assumed to be reliable, and clients are not
always active at the same time. Hence, any distributed data exchanges must
be designed to be able to cope with temporary network partitions and system
outages.
• Scalability: The number of recipients may not be known at the time the data is
sent. This number could also become very large and increase access requests in
unexpected ways. This, in turn, may harm throughput and response times. Scal-
ing up the amount of data can be an issue: the amount of data to be exchanged
may grow unboundedly and beyond the capacity limits of individual messages
(as defined by the communication and integration protocols used).
• Storage space efficiency: The data to be exchanged has to be stored some-
where along its way, and sufficient storage space must be available. The amount
of data to be shared must be known, as there may be limits on how much data
can be transferred or stored due to bandwidth constraints.
• Latency: Direct communication tends to be faster than indirect communica-
tion via relays or intermediaries.
• Ownership management: Ownership of the exchanged information has to be
established to achieve explicit control over its availability life cycle. The initial
owner is the participant sharing the data; however, there may be different par-
ties responsible for cleanup: the original sender (interested in maximizing the
reach of the shared data), the intended recipient (who may or not want to read
it multiple times), or the host of the transfer resource (who must keep storage
costs in check).
One could think of using publish-subscribe mechanisms, as offered by mes-
sage-oriented middleware (MOM) such as ActiveMQ, Apache Kafka, or
Rabbit MQ, but then the clients would have to run their own local messaging
system endpoint to receive and process incoming messages. MOM needs to be
installed and operated, which adds to the overall systems management effort
[Hohpe 2003].
208 Chapter 5 Define Endpoint Types and Operations
How It Works
Share the address of the transfer resource with the clients. Decide on data owner-
ship and its transfer; prefer client ownership over provider ownership here.
Multiple applications (API clients) can use the shared Data Transfer Resource
as a medium to exchange information that is originally created by one of them and
then transferred to the shared resource. Once the information has been published in
the shared resource, any additional client that knows the URI of the shared resource
and is authorized to do so may retrieve it, update it, add to it, and delete it (when the
data is no longer useful for any client application). Figure 5.13 sketches this solution.
fetch
API Client D
Data Store
KeyValueStore
+ save(URI, DTR)
+ load(URI): DTR
Figure 5.13 DATA TRANSFER RESOURCE. A DATA TRANSFER RESOURCE endpoint holds
temporary data to decouple two or more API clients sharing this data. The pattern instance
provides a data exchange space between these clients. Data ownership remains with the
application clients
Endpoint Roles (aka Service Granularity) 209
The shared Data Transfer Resource establishes a blackboard between its cli-
ents, providing them with an asynchronous, virtual data flow channel to mediate all
their interactions. As a result, clients can exchange data without having to connect
directly to each other, or (perhaps even more important) without having to address
each other directly and without being up and running at the same time. Hence, it
decouples them in time (they do not have to be available at the same time) and makes
their location irrelevant—as long as they all can reach the shared Data Transfer
Resource.
How do clients negotiate the URI for the shared resource? Clients may need to
agree in advance about the shared resource address, or they may dynamically discover
it using a dedicated Link Lookup Resource. Also, it is possible that the first client
sets the URI while publishing the original content and informs the others about it via
some other communication channel, or, again, by registering the address with a Link
Lookup Resource, whose identity has been agreed upon in advance by all clients.
HTTP Support for the Pattern From an implementation perspective, this solu-
tion is directly supported in HTTP, whereby Client A first performs a PUT request
to publish the information on the shared resource, uniquely identified by a URI, and
then Client B performs a GET request to fetch it from the shared resource. Note that
the information published on the shared resource does not disappear as long as no
clients perform an explicit DELETE request. Client A publishing the information to
the shared resource can do so reliably, as the HTTP PUT request is idempotent. Like-
wise, if the subsequent GET request fails, Client B may simply retry it to be able to
read the shared information eventually. Figure 5.14 illustrates the HTTP realization
of the pattern.
Clients cannot know whether other clients have retrieved the information from
the shared resource. To address this limitation, the shared resource can track access
traffic and offer additional metadata about the delivery status so that it is possible to
inquire whether and how many times the information has been fetched after it has
been published. Such Metadata Elements exposed by Retrieval Operations may
also help with the garbage collection of shared resources that are no longer in use.
Variants Access patterns and resource lifetimes may differ, which suggests the fol-
lowing variants of this pattern:
1. Relay Resource: There are two clients only, one that writes and one that reads.
Data ownership is shifted from the writer to the reader. Figure 5.15 illustrates
this variant.
210 Chapter 5 Define Endpoint Types and Operations
PUT()
GET()
GET()
2. Published Resource: One client writes as before, but then a very large, unpre-
dictable number of clients read it at different times (maybe years later), as
shown in Figure 5.16. The original writer determines how long the shared
resource remains publicly available to its multiple readers. Routing patterns
such as “Recipient List” can be supported this way [Hohpe 2003]; streaming
middleware may realize this variant.
3. Conversation Resource: Many clients read, write, and eventually delete the
shared resource (Figure 5.17). Any participant owns the transfer resource (and
can therefore both update and delete it).
Endpoint Roles (aka Service Granularity) 211
Client B
«call»
GET
«call»
GET
Client D
Client A Client B
«call» «call»
PUT GET
Conversation
Resource
«call» «call»
GET,PUT GET,DELETE
Client C Client D
Example
The example in Figure 5.18 instantiates the pattern for an integration interface in the
Lakeside Mutual sample case. The Claim Reception System Of Engagement is the
data source, and a Claim Transfer Resource decouples the two data sinks Claim Pro-
cessing System Of Records and Fraud Detection Archive from it.
ClaimReceptionSystemOfEngagement
ClaimProcessingSystemOfRecords FraudDetectionArchive
Figure 5.18 Claims management data flow as an example of a DATA TRANSFER RESOURCE
Discussion
The pattern combines the benefits of messaging and shared data repositories: flexi-
bility of data flow and asynchrony [Pautasso 2018]. Let us go through the forces and
pattern properties one by one (in the context of HTTP and Web APIs).
a) They are clients and therefore are not supposed to receive any incoming
requests.
b) They are running behind a firewall/NAT that allows only outgoing
connections.
c) They are running inside a Web browser, which only allows sending HTTP
requests to and receiving responses from a Web server.
d) They are not running at the same time.
If direct connectivity is impossible, then an indirect route may still work. The
shared Data Transfer Resource provides such an intermediary element and
can serve as a joint storage space, which is reachable from both clients and
remains available even when some of the clients temporarily disappear.
• Reliability: When using messaging systems, the connection from the client to
the middleware can be a local one (the messaging system broker process then
takes care of the remote messaging, guaranteeing message delivery). Such “pro-
gramming without a call stack” is conceptually harder and more error prone
than blocking remote procedure invocations, but it is also more powerful when
done properly [Hohpe 2003]. When applying the Data Transfer Resource
pattern, the client-to-resource connection always is a remote one. Moreover,
HTTP cannot guarantee message delivery. However, the idempotence of the
PUT and GET methods in HTTP can mitigate the problem because the send-
ing clients can retry calls to the Data Transfer Resource until the upload or
download succeeds. When using such idempotent HTTP methods to access
the shared resource, neither the middleware nor the receiver has to detect and
remove duplicate messages.
• Scalability: The amount of data that can be stored on a Web resource is bound
by the capacity of the data storage/file system that underlies the Web server.
The amount of data that can be transferred to and from the Web resource
within one standard HTTP request/response is virtually unlimited according
to the protocol and therefore constrained only by the underlying middleware
implementations and hardware capacity. The same constraints also apply for
the number of clients.
• Storage space efficiency: The Data Transfer Resource provider has to allo-
cate sufficient space.
• Latency: Indirect communication requires two hops between participants,
which, however, do not have to be available at the same time. In this pattern,
214 Chapter 5 Define Endpoint Types and Operations
the ability to transfer data across large periods and multiple participants takes
priority over the performance of the individual transfer.
• Ownership management: Depending on the pattern variant, data owner-
ship—the right but also the obligation to ensure the validity of the shared
resource content and to clean it up eventually—can stay with the source, be
shared among all parties aware of its URI, or be transferred to the Data Trans-
fer Resource. The latter option is adequate if the source originally publishing
the data is not expected to be present until all recipients have had a chance to
read it.
Once a Data Transfer Resource has been introduced, additional design issues
arise:
Related Patterns
The pattern differs from other types of Information Holder Resources with
respect to data access and storage ownership. The Data Transfer Resource acts
both as a data source and a data sink. The Data Transfer Resource exclusively
owns and controls its own data store; the only way to access its content is via the
published API of the Data Transfer Resource. Instances of other Information
Holder Resource types often work with data that is accessed and possibly even
owned by other parties (such as backend systems and their non-API clients). A Link
Lookup Resource can be seen as a Data Transfer Resource that holds a special
type of data, namely addresses (or Link Elements).
Patterns for asynchronous messaging are described in Enterprise Integration Pat-
terns [Hohpe 2003]. Some of these patterns are closely related to Data Transfer
Resource. A Data Transfer Resource can be seen as a Web-based realization
of a “Message Channel,” supporting message routing and transformation, as well
as several message consumption options (“Competing Consumers” and “Idempo-
tent Receiver”). Queue-based messaging and Web-based software connectors (as
described by this Data Transfer Resource pattern) can be seen as two different but
related integration styles; these styles are compared in “The Web as a Software Con-
nector” [Pautasso 2018].
“Blackboard” is a POSA 1 pattern [Buschmann 1996], intended to be eligible in a
different context but similar in its solution sketch. Remoting Patterns [Voelter 2004]
describes the remoting style “Shared Repository”; our Data Transfer Resource
can be seen as the API for a Web-flavored shared repository.
More Information
“Interfacer” is a role stereotype in RDD that describes a related but more generic
programming-level concept [Wirfs-Brock 2002].
Operation Responsibilities
An API endpoint exposes one or more operations in its contract. These operations
show some recurring patterns in the way they work with provider-side state. The
four operations responsibility patterns are Computation Function, State Crea-
tion Operation, Retrieval Operation, and State Transition Operation.
Figure 5.19 gives an overview of these patterns, including their variants.
216 Chapter 5 Define Endpoint Types and Operations
Operation Responsibilities
+ performFully(InParameters): OutParameters
+ undo(InParameters): OutParameters
Note that we call state-preserving API responsibilities functions (as they just get
some self-contained work done on behalf of a client) and state-changing responsibil-
ities operations (as they become active because the client hands in some data, which
is then processed and stored; it can be retrieved as well).
A A’
Pattern:
statE CrEation oPEration
An immediate response can be returned, which might just be a simple “got it”
acknowledgment.
How can an API provider allow its clients to report that something has hap-
pened that the provider needs to know about, for instance, to trigger instant or
later processing?
One could simply add yet another API operation to an endpoint without making
its state read-write profile explicit. If this is done, the specific integration needs and
concerns described previously still have to be described in the API documentation
and usage examples; there is a risk of making implicit assumptions that get forgot-
ten over time. Such an informal, ad hoc approach to API design and documentation
can cause undesired extra efforts for client developers and API maintainers when
they find out that their assumptions about effects on state and operation pre- and
postconditions no longer hold. Furthermore, cohesion within the endpoint might be
6. Time synchronization is a general theoretical limitation and challenge in any distributed system; logi-
cal clocks have been invented for that reason.
218 Chapter 5 Define Endpoint Types and Operations
harmed. Load balancing becomes more complicated if stateful operations and state-
less operations appear in the same endpoint. Operations staff must guess where and
how to deploy the endpoint implementation (for instance, in certain cloud environ-
ments and container managers).
How It Works
Add a State Creation Operation sco: in -> (out,S') that has a write-
only nature to the API endpoint, which may be a Processing Resource or an
Information Holder Resource.
Let such a State Creation Operation represent a single business incident that
does not mandate a business-level reaction from the provider-side endpoint; it may
simply store the data or perform further processing in the API implementation or an
underlying backend. Let the client receive a mere “got it” acknowledgment or identi-
fier (for instance, to be able to inquire about the state in the future and to resend the
incident report in case of transmission problems).
Such operations might have to read some state, for instance, to check for duplicate
keys in existing data before creation, but their main purpose should be state creation.
This intent is sketched in Figure 5.20.
API Client
«call»
API
+ create()
+ initiateProcess()
Figure 5.20 A STATE CREATION OPERATION has the responsibility to write to provider-side
storage but cannot read from it
Operation Responsibilities 219
Describe the abstract and the concrete syntax as well as the semantics of the inci-
dent report (the incoming state creation messages, that is) and the acknowledging
response (if any) in the API Description. Express the operation behavior in pre- and
postconditions.
State Creation Operations may or may not have fire-and-forget semantics.
In the latter case, give each state item caused by calls to instances of this pattern a
unique id (for duplicate detection and removal). Include a timestamp to capture the
time when the reported incident happened (according to the client-side clock).
Unless you write to an append-only event store, perform the required write/insert
operation in its own system transaction whose boundaries match that of the API
operation (but are not visible to the API client). Let the processing of the State Cre-
ation Operation appear to be idempotent.
The request messages accepted by a State Creation Operation contain the
full data set that is required to describe the incident that has happened, often in the
form of a Parameter Tree, possibly including Metadata Elements that annotate
other Data Elements. The response message typically contains only a basic and
simple “report received” element, for instance, an Atomic Parameter containing an
explicit acknowledgment flag (of Boolean type). Sometimes, an Atomic Parameter
List combining an error code with an error message is used, thus forming an Error
Report.
Event Notification Operations and event sourcing can form the base of event-
driven architectures (EDAs). Other pattern languages provide advice for EDA design
[Richardson 2016].
A second variant of this pattern is a Bulk Report. The client combines multiple
related incident events into one report and sends this report as a Request Bundle.
The bundle entries may all pertain to the same entity or may refer to different ones,
for instance, when creating a snapshot or an audit log from the individual events in
the Bulk Report or when passing a journal of events that occurred in a certain period
on to a data warehouse or data lake.
Examples
In the online shopping scenario, messages such as “new product XYZ created” sent
from a product management system or “customer has checked out order 123” from
an online shop qualify as examples.
Figure 5.21 gives an example in the Lakeside Mutual case. The events received
by the State Creation Operation report that a particular customer has been con-
tacted, for instance by a sales agent.
«Processing Resource»
CustomerEventProcessorExample
«StateCreationOperation»
+ informAbout(CustomerContactedEvent)
emits
«Domain Event»
CustomerContactedEvent
- customerId
- agentName
- timestamp
- conversationSummary
Discussion
Loose coupling is promoted because client and provider do not share any application
state; the API client merely informs the provider about incidents on its side. Provider-
side consistency checks might be difficult to implement because state reads are sup-
posed to be avoided in State Creation Operations (for instance, if scaling APIs and
their endpoints up and out is desired). Hence, consistency cannot always be fully
ensured when operations are defined as write-only (for instance, how should events
reporting contradictory information be dealt with?). Time management remains a dif-
ficult design task for the same reason. Reliability might suffer if no acknowledgment or
state identifier is returned; if it is returned, the API client has to make sure to interpret
it correctly (for instance, to avoid unnecessary or premature resending of messages).
Exposing write-only API operations with business semantics that report external
events is a key principle of EDAs; we discussed it in the context of the Event Noti-
fication Operation variant. In replication scenarios, events represent state changes
that have to be propagated among the replicas.
The pattern leaves some room for interpretation when implementing it:
• What should be done with arriving reports: should they be simply stored
locally, processed further, or passed on? Does provider-side state have to be
accessed, even if it is not desired, for instance, to check the uniqueness of keys?
• Does the report processing change the behavior of future calls to other opera-
tions in the same endpoint?
• Is operation invocation idempotent? Events can get lost, for instance, in the
case of unreliable network connections or temporary server outages, and might
be transmitted multiple times if the client attempts to resend unacknowledged
ones. How is consistency ensured in such situations? Strict and eventual con-
sistency are two of the options here [Fehling 2014].
Related Patterns
The endpoint role patterns Processing Resource and Information Holder
Resource typically contain at least one State Creation Operation (unless they are
222 Chapter 5 Define Endpoint Types and Operations
More Information
Instances of this pattern may trigger long-running and therefore stateful conversa-
tions [Hohpe 2007; Pautasso 2016]. The State Transition Operation pattern
covers this usage scenario.
Martin Fowler describes “Command Query Responsibility Segregation” (CQRS)
[Fowler 2011] and event sourcing [Fowler 2006]. The Context Mapper DSL and tools
support DDD and event modeling, model refactoring, as well as diagram and service
contract generation [Kapferer 2021].
DPR features a seven-step service design method to carve out API endpoints and
their operations [Zimmermann 2021b].
Pattern:
rEtriEVaL oPEration
customer profile group). The information need arises either ad hoc or regularly, for
instance, at the end of a certain period (such as week, month, quarter, or year).
How can information available from a remote party (the API provider, that is)
be retrieved to satisfy an information need of an end user or to allow further
client-side processing?
• How can data model differences be overcome, and how can data be aggregated
and combined with information from other sources?
• How can clients influence the scope and the selection criteria for the retrieval
results?
• How can the timeframe for reports be specified?
Veracity, Variety, Velocity, and Volume: Data comes in many forms, and client
interest in it varies in terms of volume, required accuracy, and processing speed. The
variability dimensions include frequency, breadth, and depth of data access. Data
production on the provider side and its usage on the client side also change over time.
Workload Management: Data processing takes time, especially if the data volume
is big and the processing power is limited. Should clients download entire databases
so that they can process their content at will locally? Should some of the process-
ing be performed on the provider-side instead so that the results can be shared and
retrieved by multiple clients?
It is hard to imagine a distributed system that does not require some kind of
retrieval and query capability. One could replicate all data to its users “behind the
scenes” periodically, but such an approach has major deficiencies with regard to con-
sistency, manageability, and data freshness, not to mention the coupling of all clients
to the fully replicated, read-only database schema.
224 Chapter 5 Define Endpoint Types and Operations
How It Works
Add a read-only operation ro: (in,S) -> out to an API endpoint, which
often is an Information Holder Resource, to request a result report that
contains a machine-readable representation of the requested information. Add
search, filter, and formatting capabilities to the operation signature.
Access the provider-side state in read-only mode. Make sure that the pattern
implementation does not change application/session state (except for access logs and
other infrastructure-level data), as shown in Figure 5.22. Document this behavior in
the API Description.
API Client
«call»
API
Retrieval
State
Operation
read state
+ findAll()
+ findById()
+ search()
Figure 5.22 A RETRIEVAL OPERATION reads from but does not write to provider-side storage.
Searching (and filtering) may be supported
For simple retrievals, one can use an Atomic Parameter List to define the query
parameters for the report and return the report as a Parameter Tree or Para-
meter Forest. In more complex scenarios, a more expressive query language (such
as GraphQL [GraphQL 2021] with its hierarchical call resolvers or SPARQL [W3C
2013], used for big data lakes) can be introduced; the query then describes the
Operation Responsibilities 225
Examples
In an online shopping example, an analytic Retrieval Operation is “show all
orders customer ABC has placed in the last 12 months.”
In the Lakeside Mutual case, we can define multiple operations to find custom-
ers and retrieve information about them as illustrated in Figure 5.23. The allData
parameter is a primitive yes/no Wish List. When set to true, an Embedded Entity
containing all customer data is included in the response; when false, a Linked
Information Holder pointing at this data is returned instead.
API
«Information Holder»
CustomerRepository
«RetrievalOperation»
+ ndById(id: ID): Customer
+ ndByArea(area: String, allData: boolean): List<Customer>
+ findByProfile(marketSegment: CustomerProfile): List<Customer>
+ getCustomerStatus(id: ID): CustomerState
+ getMonthlyCRMReport(month: Month): ReportDTR
@GET
public ClaimsDTO listClaims(
@QueryParam("limit") @DefaultValue("3") Integer limit,
@QueryParam("offset")@DefaultValue("0") Integer offset,
@QueryParam("orderBy") String orderBy
) {
List<ClaimDTO> result = […]
return new ClaimsDTO(
limit, offset, claims.getSize(), orderBy, result);
}
Variants Several variants of this pattern exist, for instance, Status Check (also
known as Progress Inquiry, Polling Operation), Time-Bound Report, and Business
Rule Validator.
A Status Check has rather simple in and out parameters (for example, two Atomic
Parameter instances): an id (for instance, a process or activity identifier) is passed in
and a numeric status code or a state name (defined in an enumeration type) is returned.
A Time-Bound Report typically specifies the time interval(s) as an additional
query parameter (or set of parameters); its responses then contain one Parameter
Tree per interval.
A Business Rule Validator is similar to the Validation Service variant of a Compu-
tation Function. However, it does not validate data that is passed on but retrieves
this data from the provider-side application state. A list of identifiers of entities
already present in the API implementation (validation target) might be included in
the request. One example of a Business Rule Validator is a check whether the pro-
vider will be able to process this business object in the current state of the conver-
sation with the client. Such a validator can be invoked prior to a call to a State
Transition Operation that primarily works on the business object that is passed
in. The validation may also include provider-side application state into the check-
ing process. In an online shopping example, “check whether all order items point to
existing products that are currently in stock” is an example of such a validator. This
Business Rule Validator helps catch errors early, which can reduce workload.
Discussion
With respect to workload management, Retrieval Operations can scale out by rep-
licating data. This is simplified by their read-only nature. Retrieval Operations
may also become a performance bottleneck, for instance, if user information needs
Operation Responsibilities 227
and query capabilities do not match and many complex calculations are required to
match information demand and supply. Network efficiency is at risk.
Pagination is commonly used to address the “volume” aspect and to reduce mes-
sage sizes. The “velocity” aspect cannot be easily supported with standard request-
reply retrievals; the introduction of streaming APIs and stream processing (which is
out of our scope here) can be considered instead.
From a security point of view, the request message often has low to medium
data protection needs in case of aggregated data retrieval; however, the request may
contain secure credentials to authorize access to sensitive information and has to
avoid DoS attacks. The response message protection requirements might be more
advanced, as returned data reports might contain business performance data or sen-
sitive personal information.7
Retrieval Operation instances are commonly exposed in Public APIs, such as
those of open data [Wikipedia 2022h] and open government data scenarios. If this is
done, they often are protected with an API Key and Rate Limits.
Time-Bound Report services can use denormalized data replicas and apply the
extract-transform-load staging commonly used in data warehouses. Such services
are common in Community APIs and Solution-Internal APIs, for example, those
supporting data analytics solutions.
Related Patterns
The endpoint pattern Processing Resource and all types of Information Holder
Resources may expose Retrieval Operations. The Pagination pattern is often
applied in Retrieval Operations.
If query responses are not self-explanatory, Metadata Elements can be intro-
duced to reduce the risk of misinterpretations on the consumer side.
The sibling patterns are State Transition Operation, State Creation Opera-
tion, and Computation Function. A State Creation Operation pushes data from
the client to the API provider, whereas a Retrieval Operation pulls data; Computa-
tion Function and State Transition Operation can support both unidirectional
data flows and bidirectional ones.
More Information
Chapter 8 in the RESTful Web Services Cookbook [Allamaraju 2010] discusses que-
ries (in the context of HTTP APIs). There is a large body of literature on database
design and information integration, including data warehouses [Kimball 2002].
7. OWASP has published an API Security Top 10 [Yalon 2019] that any API should respect, especially
those dealing with sensitive and/or classified data.
228 Chapter 5 Define Endpoint Types and Operations
A A’
Pattern:
statE transition oPEration
How can a client initiate a processing action that causes the provider-side
application state to change?
How can API clients and API providers share the responsibilities required to
execute and control business processes and their activities in a distributed
approach to business process management?
• How can API clients ask an API provider to take over certain functions that
represent business activities of varying granularities, from atomic activities to
subprocesses to entire processes, but still own the process state?
• How can API clients initiate, control, and follow the asynchronous execution
of remote business processes (including subprocesses and activities) exposed
and owned by an API provider?
Operation Responsibilities 229
The process instances and the state ownership can lie with the API client
(frontend BPM) or the API provider (BPM services), or they can be shared
responsibilities.
A canonical example process from the insurance domain is claim processing,
with activities such as initial validation of a received claim form, fraud check, addi-
tional customer correspondence, accept/reject decision, payment/settlement, and
archiving. Instances of this process can live for days to months or even years. Process
instance state has to be managed; some parts of the processing can run in parallel,
whereas others have to be executed one by one sequentially. When dealing with such
complex domain semantics, the control and data flow depends on a number of fac-
tors. Multiple systems and services may be involved along the way, each exposing one
or more APIs. Other services and application frontends may act as API clients.
The following forces have to be resolved when representing business processes and
their activities as API operations or, more generally speaking, when updating pro-
vider-side application state: service granularity; consistency; dependencies on state
changes being made beforehand, which may collide with other state changes; work-
load management; and networking efficiency versus data parsimony. Time manage-
ment and reliability also qualify as forces of this pattern; these design concerns are
discussed in the pattern State Creation Operation.
• Service granularity: Large business services may contain complex and rich
state information, updated only in a few transitions, while smaller ones may
be simple but chatty in terms of their state transitions. It is not clear per se
whether an entire business process, its subprocesses, or its individual activi-
ties should be exposed as operations of a Processing Resource. The data-
oriented services provided by Information Holder Resources also come in
different granularities, from simple attribute lookups to complex queries and
from single-attribute updates to bulk uploads of rich, comprehensive data sets.
• Consistency and auditability: Process instances are often subject to audit;
depending on the current process instance state, certain activities must not
be performed. Some activities have to be completed in a certain time window
because they require resources that have to be reserved and then allocated.
When things go wrong, some activities might have to be undone to bring the
process instance and backend resources (such as business objects and database
entities) back into a consistent state.
• Dependencies on state changes being made beforehand: State-changing API
operations may collide with state changes already initiated by other system
parts. Examples of such conflicting changes are system transactions triggered
by other API clients, by external events in downstream systems, or by provider-
internal batch jobs. Coordination and conflict resolution might be required.
230 Chapter 5 Define Endpoint Types and Operations
One could decide to ban provider-side application state entirely. This is only real-
istic in trivial application scenarios such as pocket calculators (not requiring any
storage) or simple translation services (working with static data). One could also
decide to expose stateless operations and transfer state to and from the endpoint
every time. The “Client Session State” pattern [Fowler 2002] describes the pros and
cons of this approach (and the REST principle of “hypertext as the engine of appli-
cation state” promotes it). It scales well but may introduce security threats with non-
trusted clients and, if state is large, cause bandwidth problems. Client programming,
testing, and maintenance become more flexible but also more complex and riskier.
Auditability suffers; for instance, it is not clear how to guarantee that all execution
flows are valid. In our order cancellation example, a valid flow would be “order
goods → pay → deliver → return goods → receive refund,” whereas “order goods →
deliver → refund” is an invalid, possibly fraudulent sequence.
How It Works
Introduce an operation in an API endpoint that combines client input and cur-
rent state to trigger a provider-side state change sto: (in,S) -> (out,S').
Model the valid state transitions within the endpoint, which may be a Process-
ing Resource or an Information Holder Resource, and check the validity
of incoming change requests and business activity requests at runtime.
API Client
«call»
API
State Transition
Operation (Business read and update State
Activity) state
+ update()
+ replace()
+ processActivity()
Figure 5.24 STATE TRANSITION OPERATIONS are stateful, both reading and writing provider-
side storage
There are two quite different types of update, full overwrite (or state replace-
ment) and partial change (or incremental update). Full overwrites often can be pro-
cessed without accessing the current state and then can be seen as instances of State
Creation Operations. Incremental change typically requires read access to state (as
described in this pattern). Upsert (update + insert) is a special case combining both
themes: attempting to replace a nonexisting entity results in creating a new one (with
232 Chapter 5 Define Endpoint Types and Operations
the identifier provided in the request message) [Higginbotham 2019]. With HTTP-
based APIs, full overwrite is typically exposed with the PUT method, while partial
change can be achieved with PATCH.
From a message representation structure point of view, the request and response
messages of State Transition Operation instances can be fine-grained (in the sim-
plest case, a single Atomic Parameter) as well as coarse-grained (nested Parameter
Trees). Their request message representations vary greatly in their complexity.
Many State Transition Operations are transactional internally. Operation
execution should be governed and protected by a transaction boundary that is iden-
tical to the API operation boundary. While this should not be visible to the client
on the technical level, it is okay to disclose it in the API documentation due to the
consequences for composition. The transaction can either be a system transaction
following the atomicity, consistency, isolation, and durability (ACID) paradigm
[Zimmermann 2007] or a saga [Richardson 2018], roughly corresponding to com-
pensation-based business transactions [Wikipedia 2022g]. If ACID is not an option,
the BASE principles or try-cancel-confirm (TCC) [Pardon 2011] can be considered; a
conscious decision between strict and eventual consistency [Fehling 2014] is required,
and a locking strategy also has to be decided upon. The transaction boundaries have
to be chosen consciously; long-running business transactions usually do not fit into a
single database transaction with ACID properties.
The processing of the State Transition Operation should appear to be idempo-
tent, for instance, by preferring absolute updates over incremental ones. For exam-
ple, “set value of x to y” is easier to process with consistent results than is “increase
value of x by y,” which could lead to data corruption if the action request gets dupli-
cated/resent. “Idempotent Receiver” in Enterprise Integration Patterns [Hohpe 2003]
provides further advice.
It should be considered to add compliance controls and other security means such
as ABAC, for instance, based on an API Key or a stronger authentication token,
to the entire API endpoint or individual State Transition Operations. This may
degrade performance caused by extra computations and data transfers.
Variant A Business Activity Processor is a variant of this pattern that can support
frontend BPM scenarios and realize BPM services as well (Figure 5.25). Note that we
use the term activity in a general sense here; activities might be rather fine-grained
and participate in larger processes (for example, accept or reject claim or proceed
to checkout in our sample scenarios) but might also be rather coarse grained (for
instance, process claim or shop online).
Operation Responsibilities 233
update/replace/processActivity()
getState()
setState()
Single activities can be responsible for any of the following fine-grained action
primitives providing process control: prepare, start, suspend/resume, complete, fail,
cancel, undo, restart, and cleanup. Given an asynchronous nature of the business
activity execution and, in the frontend BPM case, client-side process ownership, it
should also be possible to receive the following events via State Transition Opera-
tions: activity finished, failed, or aborted; and state transition occurred.
Figure 5.26 assembles the action primitives and states into a generic state machine
modeling the behavior of Processing Resources and their State Transition Oper-
ations in the Business Activity Processor variant. Depending on the complexity of
their behavior, instances of Information Holder Resources can also be specified,
implemented, tested, and documented this way.
234 Chapter 5 Define Endpoint Types and Operations
Initial
prepare
Ready
start
Running Suspended
suspend
resume
undo
complete
fail restart restart
Final
• Prepare (or initialize): This primitive allows clients to prepare the execution
of a state-changing activity by transferring the input prior to the actual activ-
ity, for instance, for validation purposes. Depending on the complexity of such
information, an initialization may involve a single call or a more complex
Operation Responsibilities 235
conversation. Once all information has been provided, the activity is “Ready”
to start and an activity identifier is assigned. This primitive can be seen as an
instance of the sibling pattern State Creation Operation.
• Start: This primitive allows clients to explicitly start the execution of an activ-
ity, which has been initialized and is ready to start. The state of the activity
becomes “Running.”
• Suspend/resume: These two primitives allow clients to pause and later con-
tinue the execution of a running activity. Suspending a running activity may
free execution resources within the API endpoint.
• Complete: This primitive transitions the activity state from “Running” to
“Finished” to indicate that the activity ended successfully.
• Fail: This activity transitions the state from “Running” to “Failed,” possibly
explained in an Error Report.
• Cancel: This primitive allows clients to interrupt the execution of the activity
and “Abort” it in case they are no longer interested in its results.
• Undo: This primitive allows compensating the actions performed by the activ-
ity, effectively reverting the state of the API endpoint back to its original one,
before the activity was started. It may not always be possible to do so, espe-
cially when activities provoke side effects that impact the outside of the API
provider. An example is an email that is sent and cannot be recalled. Note that
we assume compensation can be done within the undo transition. In some
cases, it may require to set up a separate activity (with its own state machine).
• Restart: This primitive allows clients to retry the execution of a failed or
aborted activity. The activity state goes back to “Running”.
• Cleanup: This primitive removes any state associated with finished, failed,
or aborted activities. The activity identifier is no longer valid and the activity
state transitions to “Final.”
In frontend BPM, API clients own the process instance state. They may inform the
API provider about the following two types of events (when exposing BPM services,
such event notifications may travel in the other direction, from the service provider
to its clients):
• Activity finished, failed, or aborted: Once the execution of the activity com-
pletes, affected parties should be notified of its successful or failed comple-
tion so that they can retrieve its output. This may happen via a call to a State
236 Chapter 5 Define Endpoint Types and Operations
Multiple State Transition Operations, often located in the same API endpoint,
can be composed to cover subprocesses or entire business processes. It has to be
decided consciously where to compose: frontend BPM often uses a Web frontend
as API client; BPM services yield composite Processing Resources exposing rather
coarse-grained State Transition Operations, effectively realizing the “Process
Manager” pattern from [Hohpe 2003]. Other options are to (1) introduce an API
Gateway [Richardson 2018] as a single integration and choreography coordination
point or (2) choreograph services in a fully decentralized fashion via peer-to-peer
calls and/or event transmission.
Executing these activities, State Transition Operations change the business
activity state in the API endpoint; the complexity of their pre- and postconditions
as well as invariants varies, depending on the business and integration scenario at
hand. Medium to high complexities of these rules are common in many application
domains and scenarios. This behavior must be specified in the API Description; the
transition primitives and state transitions should be made explicit in it.
When realizing the pattern and its Business Activity Processor variant in HTTP,
suitable verbs (POST, PUT, PATCH, or DELETE) should be picked from the uniform
REST interface options. Process instance and activity identifiers typically appear
in the URI as an Id Element. This makes it easy to retrieve status information via
HTTP GET. Each action primitive can be supported by a separate State Transition
Operation; alternatively, the primitive can be provided as an input parameter to a
more general process management operation. In HTTP resource APIs, process iden-
tifier and primitive name often are transported as path parameters; the same holds
for the activity identifier. Link Elements and URIs then advance the activity state
and inform affected parties about subsequent and alternative activities, compensa-
tion opportunities, and so on.
Operation Responsibilities 237
Example
The activity “proceed to checkout and pay” in an online shop illustrates the pattern
in an order management process. “Add item to shopping basket” is an activity in the
“product catalog browsing” subprocess. These operations do change provider-side
state, they do convey business semantics, and they do have nontrivial pre- and post-
conditions as well as invariants (for instance, “do not deliver the goods and invoice
the customer before the customer has checked out and confirmed the order”). Some
of these might be long running too, thus requiring fine-grained activity status con-
trol and transfer.
The following example from the Lakeside Mutual case, shown in Figure 5.27,
illustrates the two extremes of activity granularity. Offers are created in a single-step
operation; claims are managed step by step, causing incremental state transitions on
the provider side. Some of the primitives from Figure 5.26 can be assigned to State
Transition Operations in the example; for instance, createClaim() corresponds to
the start primitive, and closeClaim() completes the business activity of claim check-
ing. The fraud check might be long running, which indicates that the API should
support the suspend and resume primitives in the corresponding State Transition
Operations of the Processing Resource for claims management.
«Processing Resource»
OfferCreationBusinessActivityProcessor
«StateTransitionOperation»
+ insureCustomer(ApplicationData): OfferDTR
«Processing Resource»
ClaimsManagementBusinessActivityProcessor
+ rejectClaim(ID): Status
+ closeClaim(ID): Status
«StateCreationOperation»
+ createClaim(ClaimDTR): ID
«StateTransitionOperation»
+ performFraudCheck(ID): Status
+ approveClaim(ID): Status
Figure 5.27 Two examples of STATE TRANSITION OPERATIONS: Coarse-grained BPM service
and fine-grained frontend BPM process execution
238 Chapter 5 Define Endpoint Types and Operations
Discussion
The design forces are resolved as follows:
• Service granularity: Processing Resources and their State Transition
Operations can accommodate both smaller and larger “service cuts” [Gysel
2016] and therefore promote agility and flexibility. Information Holder
Resources come in different sizes too. The impact of the endpoint sizing deci-
sions on coupling and other qualities was discussed previously in these two
patterns. The fact that such states are explicitly modeled as part of the API
Description makes it possible to track them in the first place.
• Consistency and auditability: State Transition Operations can and must
handle business and system transaction management internally in the API
implementation; the chosen design options, discussed previously, and their
realization determine whether the pattern instance is able to resolve these
forces and meet its requirements. Similarly, API implementation-internal log-
ging and monitoring support auditability.
• Dependencies on state changes made beforehand: State changes may collide
with each other. The API providers should check the validity of a requested
state transition, and clients should expect that their state transition requests
might be denied due to their out-of-date assumptions about the current state.
• Workload management: Stateful State Transition Operations cannot scale
easily, and endpoints featuring such operations cannot be relocated to other
compute nodes (hosting servers) seamlessly. This is particularly relevant when
deploying to clouds because cloud features such as elasticity and autoscaling
can be leveraged only if the deployed application is designed for them. Manag-
ing process instance state is delicate by design; its intricacies do not necessarily
suggest that it is easy to feel at home in a cloud.8
• Networking efficiency versus data parsimony: A RESTful API design of
frontend BPM and BPM services can use state transfers from clients to pro-
viders and resource designs to come up with a suitable balance between
expressiveness and efficiency. The choice between incremental updates (small,
nonidempotent messages) or replacement updates (larger but idempotent mes-
sages) influences the message sizes and exchange frequency.
8. Serverless cloud functions, for instance, seem to be better suited for other usage scenarios.
Operation Responsibilities 239
Related Patterns
The pattern differs from its siblings as follows: A Computation Function does not
touch the provider-side application state (read or write) at all; a State Creation
Operation only writes to it (in append mode). Instances of Retrieval Operation
read but do not write to it; State Transition Operation instances both read and
write the provider-side state. Retrieval Operation pulls information from the pro-
vider; State Creation Operations push updates to the provider. State Transition
Operations may push and/or pull. A State Transition Operation may refer to a
provider-side state element in its request message (for instance, an order id or a serial
number of a staff member); State Creation Operations usually do not do this
(except for technical reasons such as preventing usage of duplicate keys or updating
audit logs). They often return Id Elements for later access.
State Transition Operations can be seen to trigger and/or realize “Business
Transactions” [Fowler 2002]. Instances of this pattern may participate in long-
running and therefore stateful conversations [Hohpe 2007]. If this is done, context
information necessary for logging and debugging often has to be propagated—for
instance, by introducing an explicit Context Representation. State Transition
Operations can use and go along with one or more of the RESTful conversation
patterns from “A Pattern Language for RESTful Conversations” [Pautasso 2016].
240 Chapter 5 Define Endpoint Types and Operations
For instance, one may want to consider factoring out the state management and the
computation parts of a process activity into separate services. Conversation patterns
or choreographies and/or orchestrations may then define the valid combinations and
execution sequences of these services.
State Transition Operations are often exposed in Community APIs; Chapter
10, “Real-World Pattern Stories,” features such a case in depth. Services-based sys-
tems expose such operations in Solution-Internal APIs as well. An API Key typi-
cally protects external access to operations that write to the provider-side state, and
a Service Level Agreement may govern their usage.
More Information
There is a large body of literature on BPM(N) and workflow management that intro-
duces concepts and technologies to implement stateful service components in gen-
eral and State Transition Operations in particular (for instance, [Leymann 2000;
Leymann 2002; Bellido 2013; Gambi 2013]).
In RDD [Wirfs-Brock 2002], State Transition Operations correspond to
“Coordinators” and “Controllers” that are encapsulated as “Service Providers”
made accessible remotely with the help of an “Interfacer.” Michael Nygard suggests
many patterns and recipes that improve reliability in Release It! [Nygard 2018a].
The seven-step service design method in DPR suggests calling out endpoint roles
and operation responsibilities such as State Transition Operation when preparing
candidate endpoint lists and refining them [Zimmermann 2021b].
?
Pattern:
ComPutation funCtion
How can a client invoke side-effect-free remote processing on the provider side
to have a result calculated from its input?
One could perform the required calculation locally, but this might require pro-
cessing large amounts of data, which in turn might slow down clients that lack the
necessary CPU/RAM capacity. Eventually, such a nondistributed approach leads to a
monolithic architecture, which will require reinstalling clients every time the calcula-
tion has to be updated.
How It Works
Introduce an API operation cf with cf: in -> out to the API endpoint,
which often is a Processing Resource. Let this Computation Function vali-
date the received request message, perform the desired function cf, and return
its result in the response.
9. These observations hold when shifting calculations from a client to an API provider in a Processing
Resource but also when outsourcing data management to an Information Holder Resource.
242 Chapter 5 Define Endpoint Types and Operations
API Client
«call»
State not accessed
API
Computation State
Function
+ calculate()
+ validate()
+ transform()
Figure 5.28 A COMPUTATION FUNCTION is stateless, neither reading nor writing to provider-
side storage
Design request and response message structures that fit the purpose of the Com-
putation Function. Include the Computation Function in the API Description
(in the context of the endpoint it is added to). Define at least one explicit precondi-
tion that references the elements in the request message and one or more postcondi-
tions that specify what the response message contains. Explain how this data should
be interpreted.
There is no need to introduce transaction management in the API implementation
because a mere Computation Function is stateless by definition.
Variants The general, rather simple Computation Function pattern has several
variants, Transformation Service and Validation Service as well as Long Running
Computation (which is more challenging technically than the general case). Each
variant requires different request/response message representations.
A Transformation Service implements one or more of the message translation
patterns from Enterprise Integration Patterns [Hohpe 2003] in a network-accessible
form. A Transformation Service does not change the meaning of the data that it pro-
cessed, but alters its representation. It might convert from one representation struc-
ture to another format (for example, customer record schemas used in two different
Operation Responsibilities 243
subsystems) or from one notation to another (for example, XML to JSON, JSON
to CSV). Transformation Services typically accept and return Parameter Trees of
varying complexity.
Validation Service is also known as (Pre-)Condition Checker. To deal with poten-
tially incorrect input, the API provider should always validate it before processing it
and make it explicit in its contract that the input may be rejected. It may be useful
for clients to be able to test their input validity explicitly and independently from the
invocation of the function for processing it. The API thus breaks down into a pair of
two operations, a Validation Service and another Computation Function:
How can an API provider check the correctness/accuracy of incoming data trans-
fer representations (parameters) and provider-side resources (and their state)?
The solution to this problem is to introduce an API operation that receives a Data
Element of any structure and complexity and returns an Atomic Parameter (for
example, a Boolean value or integer) that represents the validation result. The vali-
dation primarily pertains to the payload of the request. If the API implementation
consults the current internal state during the validation, the Validation Service
becomes a variant of a Retrieval Operation (for instance, to look up certain values
and calculation rules), as shown in Figure 5.29.
Operation Responsibilities
Validation Service
Figure 5.29 Validation Service variant: Arbitrary request data, Boolean response
(DTR: data transfer representation)
244 Chapter 5 Define Endpoint Types and Operations
Two exemplary requests are “Is this a valid insurance claim?” and “Will you be
able to accept this purchase order?” invoked prior to a call to a State Transition
Operation in our sample scenarios. In case of such “pre-activity validation,” the
parameter types can be complex (depending on the activity to be prevalidated); the
response might contain suggestions on how to correct any errors that were reported.
There are many other types of conditions and items worth validating, ranging
from classifications and categorizations such as isValidOrder(orderDTR) and
status checks such as isOrderClosed(orderId) to complex compliance checks
such as has4EyesPrinicipleBeenApplied(...). Such validations typically
return rather simple results (such as a success indicator and possibly some additional
explanations); they are stateless and operate on the received request data exclusively,
which makes them easy to scale and move from one deployment node to another.
The third variant is Long Running Computation. A simple function operation
may be sufficient under the following assumptions:
However, sometimes the processing will take a noticeable amount of time, and
sometimes it cannot be assured that the processing time of a computation will be
short enough (for instance, due to unpredictable workload or resource availability
on the API provider side or due to varying sizes of input data sent by the client).
In such cases, clients should be provided some form of asynchronous, nonblocking
invocation of a processing function. A more refined design is needed for such Long
Running Computations, which may receive invalid input and may require investing a
significant amount of CPU time to execute.
There are different ways of implementing this pattern variant:
1. Call over asynchronous messaging. The client sends its input via a request mes-
sage queue, and the API provider puts the output on a response message queue
[Hohpe 2003].
2. Call followed by callback. The input is sent via a first call, and the result is sent
via a callback, which assumes that clients support callbacks [Voelter 2004].
Operation Responsibilities 245
Examples
A simple, rather self-explanatory example of a Transformation Service is shown in
Figure 5.30.
API
«Processing Resource»
GeoComputationAndValidationUtility
«ComputationFunction»
+ calculateDistance(from: AddressDTR, to: AddressDTR): ResultDTR
«TransformationService»
+ milestoKilometers(ukDistance: int): int
«ValidationService»
+ isAddressValid(address: AddressDTR): boolean
An operation to find out about the health of a service is called heartbeat. Such a
test message is an example of a simple command exposed remotely within a Pro-
cessing Resource endpoint (see Figure 5.31).
246 Chapter 5 Define Endpoint Types and Operations
Watchdog
«Processing Resource»
ManagedBusinessApplicationEndpoint
«ComputationFunction»
+ testConnectivity(): boolean
+ testAvailability(testMessage: String): OperationalStatus
Discussion
Reproducibility and trust suffer because an external dependency is introduced that
cannot be controlled by the client; it has to trust the provider that multiple subse-
quent calls will be answered coherently. The decision to outsource functionality must
be compliant with legislation and inhouse policies, for instance, those about data
protection and software licensing.
Performance is negatively impacted due to the network latency. Message sizes
might increase because stateless servers cannot retrieve any intermediate results from
their own data stores. Still, it may also occur that for the given computation, the per-
formance penalty due to the network may be compensated by the faster computation
time on the provider side and thus make it worthwhile to offload the computation
Operation Responsibilities 247
Related Patterns
The “Service” pattern in DDD covers similar semantics (but is broader and targets
the business logic layer of an application). It can help identify Computation Func-
tion candidates during endpoint identification [Vernon 2013].
248 Chapter 5 Define Endpoint Types and Operations
More Information
Service types are a topic covered by SOA literature from the early 2000s, such as
Enterprise SOA [Krafzig 2004] and SOA in Practice [Josuttis 2007]. While the service
type taxonomies in these books are more focused on the overall architecture, some of
the basic services and utility services have responsibilities that do not require read or
write access to provider/server state and therefore qualify as instances of this pattern
and its variants.
The design-by-contract approach in the object-oriented programming method
and language Eiffel [Meyer 1997] includes validation into the codification of business
commands and domain methods and automates pre- and postcondition checking.
This program-internal approach can be seen as an alternative to external Validation
Services (but also as a rather advanced known use of it).
A lot of online resources on serverless computing exist. One starting point is Jer-
emy Daly’s Web site and blog Serverless [Daly 2021].
Summary
This chapter presented patterns that address API architectural concerns. We speci-
fied endpoint roles and operation responsibilities in the early steps of an API design
such as those in the Define phase of the ADDR process.
The roles and responsibilities help clarify the architectural significance of these
API design elements and serve as input to the following phases. Chapter 3, “API Deci-
sion Narratives,” covered the questions, options, and criteria eligible when designing
endpoints and operations in a role- and responsibility-driven way; complementary to
that discussion, this chapter provided the full pattern texts.
Following the pattern template introduced in Chapter 4, we covered data-oriented
API endpoint roles:
10. The RESTful Web Services Cookbook mentions such controller resources explicitly [Allamaraju
2010].
250 Chapter 5 Define Endpoint Types and Operations
an API can be called and what the client can expect to be returned (assuming that a
response is sent).
Software Systems Architecture: Working with Stakeholders Using Viewpoints and
Perspectives [Rozanski 2005] has an information viewpoint. “Data on the Outside
versus Data on the Inside” [Helland 2005] explains design forces and constraints for
data exposed in APIs and application-internal data. While not specific to APIs and
service-oriented systems, Release It! captures a number of patterns that promote sta-
bility (including reliability and manageability). Examples include “Circuit Breaker”
and “Bulkhead” [Nygard 2018a]. Site Reliability Engineering [Beyer 2016] reports
how Google runs production systems.
Next up are the responsibilities of message representations elements—and their
structure (Chapter 6, “Design Request and Response Message Representations”).
This page intentionally left blank
Chapter 6
Having defined API endpoints and their operations in the previous chapter, we now
look into the request and response messages that the API clients and providers
exchange. These messages are a key part of the API contract; they bring or break
interoperability. Large and rich messages might be very informative, but they also
add runtime overhead; small and terse messages might be efficient to transport, but
they might not be understood easily and may cause clients to emit follow-up requests
to fully satisfy their information needs.
We start with a discussion of related design challenges and then introduce pat-
terns responding to these challenges. The patterns are presented in two sections,
“Element Stereotypes” and “Special-Purpose Representations.”
This chapter corresponds to the Design phase of the Align-Define-Design-Refine
(ADDR) process that we reviewed at the beginning of Part 2.
253
254 Chapter 6 Design Request and Response Message Representations
offer other ways to transport data. For example, HTTP allows transmitting key-
value pairs as headers but also as path, query, and cookie parameters.
One might think that knowing about these different ways to exchange informa-
tion is sufficient to design request and response messages. But if we look closer, we
can detect recurring usage patterns in the message representation elements, leading
to the following questions:
What are the meanings of the message elements? Can these meanings be
stereotyped?
Which responsibilities within conversations do certain message elements have?
Which quality goals do they help satisfy?
The patterns in this chapter answer these questions by first inspecting individual
elements and then looking at composite representations for specific usage scenarios.
• Developer convenience and experience on both the consumer and the provider
sides, defined in terms of function, stability, ease of use, and clarity (includ-
ing learning and programming effort). The wants and needs of these two sides
often conflict. For instance, a data structure that is easy to create and populate
might be difficult to read; a compact format that is light in transfer might be
difficult to document, prepare, understand, and parse.
Element Stereotypes
aggregates
Error Data
ide
Report ntif Element
ied
by
uses
Link Context
Element Representation
Figure 6.1 Pattern map for this chapter: Element stereotypes and their relations to other
patterns
Element Stereotypes
The four patterns expressing data responsibilities are Data Element, Metadata
Element, Id Element, and Link Element. These element stereotypes give meaning
to the parts of request and response message representations.
Element Stereotypes 257
Pattern:
data ELEmEnt
The exchanged data may or may not be involved in reading and writing the
provider-side application state and data in the API implementation. Such relations
should not be visible to the client.
How can API client and API provider implementation be decoupled from a
data management point of view?
How It Works
1. Also see discussions about Semantic Versioning, API Description (including technical service con-
tracts), Wish List, and Service Level Agreement in Chapters 7, 8, and 9.
2. Distributed objects and other forms of remote references are core concepts in the integration style
“Remote Procedure Invocation” [Hohpe 2003].
Element Stereotypes 259
Element Stereotypes
Figure 6.2 DATA ELEMENTS can either be generic or typed, providing supplemental
information optionally
3. According to our API domain model from Chapter 1, these data transfer representations (DTRs) are
wire-level equivalents of program-level data transfer objects (DTOs) described by [Daigneau 2011] and
[Fowler 2002].
260 Chapter 6 Design Request and Response Message Representations
Example
The following excerpt from the solution-internal API of a customer relationship
management (CRM) system features strongly typed Data Elements: a structured
one, name, and a flat, textual one, phoneNumber (contract notation: Microservice
Domain-Specific Language (MDSL), introduced in Appendix C):
Customer is a Parameter Tree that combines the two data elements. The exam-
ple also features an Atomic Parameter and Id Element: customerId. Note that
Element Stereotypes 261
these data representations might have been specified in a domain model first; that
said, the domain model elements used for the API implementation should not be
exposed directly without wrapping and/or mapping them; loose coupling of the cli-
ent, interface, and implementation is desired.
Discussion
A rich, deeply structured Published Language is expressive but also hard to secure
and maintain; a simple one can be taught and understood easily but may not be able
to represent the domain specifics adequately. This set of trade-offs makes API design
hard; answering the data contract granularity question is nontrivial.
Reasonable compromises regarding these conflicting forces require an itera-
tive and incremental approach to pattern selection and adoption; best practices on
DDD in service design have been published and should be considered [Vernon 2013];
Appendix A summarizes some of these and adds our own insights. The use of many
domain-driven Data Elements makes APIs expressive so that clients can find and
use what they need easily.
Security and data privacy can be improved by exposing as few Data Elements
as possible. Lean interfaces also promote maintainability and ease of configuration
(that is, flexibility on the provider side). “Less is more” and “if in doubt, leave it out”
are rules of thumb when defining secure data contracts in APIs. The “less is more”
philosophy may limit expressiveness, but it promotes understandability. The entity
data must be included in any security analysis and design activities, such as threat
modeling, security and compliance by design, penetration testing, and compliance
audits [Julisch 2011]. This is an essential point because sensitive information may be
leaked otherwise.
Using the same Data Element structures across an entire API or a set of in-house
services allows for easier composition of the services. Enterprise Integration Patterns
calls such an approach a “Canonical Data Model” but advises to handle it with care
[Hohpe 2003]. One can consider microformats [Microformats 2022] in such a stand-
ardization effort.
If many related/nested Data Elements are defined, some of which are optional,
processing becomes complicated; performance and testability are impaired. While
client-side flexibility is high initially, things get difficult when the rich API starts to
change over time.
Organizational patterns (and antipatterns), such as the “not invented here” syn-
drome and “fiefdoms” or “power games,” often lead to overengineered, unnecessar-
ily complex abstractions. Simply exposing such abstractions via a new API (without
putting “Anti-Corruption Layers” [Evans 2003] in place that hide complexity) is
bound to fail in the long run. Project schedules and budgets are at risk in such cases.
262 Chapter 6 Design Request and Response Message Representations
Related Patterns
A Data Element can contain instances of the “Value Object” pattern in DDD
[Evans 2003] in transit; DDD “Entity” is represented as a variant of our pattern.
That said, one should be aware that instances of DDD patterns should not be trans-
lated into API designs one-to-one. While an Anti-Corruption Layer can protect the
downstream participant in a relation (here, API client), the upstream (here, API pro-
vider) should design its Published Language in such a way that undesired coupling is
minimized [Vernon 2013].
It might make sense to have different representations for the same entity depend-
ing on the context it is used in. For example, a customer is a widespread business
concept modeled as an entity in many domain models; typically, many of its attrib-
utes are relevant only in certain use cases (for example, account information for the
payment domain). In that case, a Wish List can let clients decide what information
they want. In HTTP resource APIs, content negotiation and custom media types
provide flexible realization options for multipurpose representations. The “Media
Type Negotiation” pattern in Service Design Patterns is related [Daigneau 2011].
Core J2EE Patterns [Alur 2013] presents a “Data Transfer Object” pattern for use
within an application boundary (for example, data transfer between tiers). Patterns
of Enterprise Application Architecture [Fowler 2002] touches on many aspects of
remote API design, such as Remote Facades and DTOs. Similarly, Eric Evans touches
on functional API aspects in DDD patterns such as “Bounded Contexts” and “Aggre-
gates” [Evans 2003]. Instances of these patterns contain multiple entities; hence,
they can be used to assemble Data Elements into coarser-grained units.
The general data modeling patterns in [Hay 1996] cover data representations but
focus on data storage and presentation rather than data transport (therefore, the dis-
cussed forces differ from ours). Domain-specific modeling archetypes for enterprise
information systems also can be found in the literature [Arlow 2004].
The “Cloud Adoption Patterns” Web site [Brown 2021] has a process pattern
called “Identify Entities and Aggregates.”
More Information
Chapter 3 in the RESTful Web Services Cookbook gives representation design advice
in the context of HTTP; for instance, recipe 3.4 discusses how to choose a represen-
tation format and a media type (with Atom being one of the options) [Allamaraju
2010].
Design Practice Reference features DDD and related agile practices eligible in API
and data contract design [Zimmermann 2021b].
Context Mapper clarifies the relationships between strategic DDD patterns in its
domain-specific language (DSL) and tools [Kapferer 2021].
Element Stereotypes 263
Pattern:
mEtadata ELEmEnt
In addition to the quality concerns discussed at the beginning of this chapter, the
impact on interoperability, coupling, and ease of use versus runtime efficiency have
to be considered.
The extra data that explains other data can be provided solely in the API Descrip-
tion. Such static and explicit metadata documentation often is sufficient; however, it
limits the ability of the message receiver to make metadata-based decisions dynami-
cally at runtime.
A second API endpoint could be introduced to inquire about metadata separately.
However, such an approach bloats the API and introduces additional documenta-
tion/training, testing, and maintenance effort.
How It Works
Introduce one or more Metadata Elements to explain and enhance the other
representation elements that appear in request and response messages. Popu-
late the values of the Metadata Elements thoroughly and consistently; use
them to steer interoperable, efficient message consumption and processing.
«Domain Class»
Message Exchange
Message
Schema
- protocolHeaders
- notationType
- schemaDefinition
bodyContent structures
Message
Payload
composedOf
Variants Three variants of this pattern exist, representing particular types and
usage of metadata we observed in APIs:
These variants are visualized in Figure 6.4. Other forms of Metadata Elements
exist (covered later).
«Pattern»
Metadata
Element
Query Parameter
- lter
Each Metadata Element can realize more than one of the variants. For instance,
a region code might give provenance information but also be used to control data pro-
cessing. Such data might act as a filter in a digital rights management scenario or be
used in “Context-Based Routers” in enterprise application integration [Hohpe 2003].
In information management, three main types of metadata are used to describe
any type of resource (such as a book or multimedia content) [Zeng 2015]: Descriptive
metadata has purposes such as discovery and identification; it can include elements
such as title, abstract, author, and keywords. Structural metadata indicates how com-
pound information elements are put together, for example, how pages (or sections)
are ordered to form chapters. Administrative metadata provides information to help
manage a resource, such as when and how it was created, what its file type and other
technical properties are, and who can access it. Two common subsets of administrative
data are rights management metadata, including intellectual property rights, and pres-
ervation metadata, which contains information used to archive a resource.
Element Stereotypes 267
Example
The following example from the Lakeside Mutual case study shows all three
metadata types: provenance (Content-Type, Date), control (the API Key b318ad-
736c6c844b in the header), and aggregated metadata (size).
Most Metadata Elements are Atomic Parameters in this example. The JSON
object _links forms a simple Parameter Tree that bundles two Atomic Param-
eters serving as Link Elements.
268 Chapter 6 Design Request and Response Message Representations
Discussion
Accuracy usually improves when the pattern is applied (assuming a correct and con-
sistent implementation). Coupling decreases on the data level but is still there on the
metadata level. Ease of use can be achieved.
Processing efficiency may suffer due to the increased message sizes. Maintain-
ability, security, and interoperability may improve but also suffer depending on the
amount, structure, and meaning of the metadata. Excessive use of such Metadata
Elements risks bloating an interface and making it more challenging to maintain
and evolve (for example, in terms of Semantic Versioning).
Defined, populated, exchanged, and interpreted wisely, Metadata Elements
can streamline receiver-side processing (by avoiding unnecessary work), improve
computation results and their display (by steering/guiding the application frontend
and the human user), and contribute to an end-to-end security model that protects
the communication participants from external and internal threats. Security meta-
data may serve as input to encryption/decryption algorithms, support integrity
checks, and so on.
Metadata can reside and be defined in several of the logical layers defined in
Patterns of Enterprise Application Architecture [Fowler 2002]. Pagination, for
instance, is a presentation layer or service layer concern; the business logic layer of
the provider-side API implementation does not care about it. The same holds for
caching of previous responses. Access/access control type of metadata typically
also is created and used on the presentation or service layer. Data provenance and
validity information such as video/audio owners and intellectual property rights
in media streaming APIs and certain types of control metadata belong to the busi-
ness logic layer. Query statistics and aggregations, on the other hand, can be seen
as data access layer (or persistence layer) information. If lower-layer metadata is
already present, API designs must decide whether to pass this metadata on or to
convert and wrap it (tradeoff: effort versus coupling).
The client should depend on metadata only when it is necessary to satisfy man-
datory functional and nonfunctional requirements. In all other cases, the available
metadata should be treated as an optional convenience feature to make API usage
more efficient; the API and its clients should still function if the metadata is not
present. For example, control metadata such as Pagination links and related page
counts will make the client depend on it once introduced. Some aggregation meta-
data, such as the size of embedded entity collections, can be calculated on the mes-
sage receiver side rather than on the provider side alternatively.
An alternative to adding metadata to request or response messages is to fore-
see a dedicated operation returning metadata about a particular API element. In
Element Stereotypes 269
such a design, an Id Element or Link Element identifies the data that is supple-
mented with metadata; the dedicated operation takes the form of a Retrieval
Operation. An even more advanced approach is to define dedicated Metadata
Information Holders as special types of Master Data Holder (or Reference
Data Holder if immutable), possibly referenced indirectly via Link Lookup
Resources.
ETags in HTTP messages, defined in RFC 7232 [Fielding 2014a] can be seen as
control and provenance metadata; expiration dates of one-time-only passwords
qualify as metadata too. The Conditional Request pattern explains and elaborates
on ETags in Chapter 7, “Refine Message Design for Quality.”
Related Patterns
A Metadata Element is a specialization of the more abstract concept of a Data
Element; not all metadata affects business logic and domain model in the API
implementation (as explained earlier). Id Elements sometimes are accompanied
by additional Metadata Elements (for instance, to classify the identifier/link or
to define an expiration time). Metadata often comes in the syntactic form of
Atomic Parameters. Several related instances of the pattern can be transported as
Atomic Parameter Lists or be included in Parameter Trees.
The Pagination pattern relies on metadata to inform the client about the current,
previous, and next result pages; the total amount of pages/results; and so on. Hyper-
media controls such as typed link relations contain metadata as well (as explained
later in the Link Element pattern).
A “Context Object” to which “Interceptors” can add their information is pre-
sented in several pattern languages, including Remoting Patterns [Voelter 2004].
Our Context Representation pattern suggests defining an API-wide, technology-
independent standard location and structure for metadata in general and control
metadata in particular.
The “Format Indicator” and “Message Expiration” information, both intro-
duced in Enterprise Integration Patterns [Hohpe 2003], rely on metadata. The same
holds for control and provenance information such as “message id” and “message
date” in messaging APIs such as Jakarta Messaging (formerly JMS). Other enter-
prise integration patterns, for instance, “Correlation Identifier” and “Routing
Slip,” can be seen as special Metadata Elements. A Correlation Identifier holds
control metadata primarily but also shares provenance metadata (because it identi-
fies a previous request message). The same holds for “Return Address” (because
it points at an endpoint or channel). “Message Filters,” “Message Selectors,” and
“Aggregators” often operate on control and provenance metadata.
270 Chapter 6 Design Request and Response Message Representations
More Information
For a general introduction to types of metadata and eligible standards, refer to the
following sources:
These metadata types are also summarized in the tutorial Metadata Basics [Zeng
2015].
Our Control Metadata Element variant corresponds to the technical type, and
use information often comes as Aggregate Metadata Element. Provenance Metadata
Elements often have an administrative, descriptive, or preservation nature.
The Zalando RESTful API and Event Scheme Guidelines [Zalando 2021] point
out the importance of OpenAPI metadata. A blog post by Steve Klabnik covers
metadata in resource representations [Klabnik 2011].
Element Stereotypes 271
Pattern:
id ELEmEnt
How can API elements be distinguished from each other at design time and at
runtime?
• Effort versus stability: In many APIs, plain character strings are used as logical
names. Such local identifiers are easy to create but may become ambiguous when
used outside their original context (for instance, when clients work with multi-
ple APIs). They might have to be changed in that case. On the contrary, global
272 Chapter 6 Design Request and Response Message Representations
identifiers are designed to last longer but require some address space coordination
and maintenance. In both cases, the namespace should be designed with care and
purpose. Changing requirements might make it necessary to rename elements,
and API versions might become incompatible with prior versions. In such cases,
certain names may no longer be unique and may therefore cause conflicts.
• Readability for machines and humans: Humans who work with identifiers
include developers, system administrators, and system and process assurance
auditors. Long, logically structured, and/or self-explanatory names are more
accessible for humans than are short, encrypted, and/or encoded ones. However,
humans often do not want to read identifiers in their entirety; for instance, the
primary audience for query parameters and session identifiers is the API imple-
mentation and supporting infrastructure, not an end user of a Web application.
• Security (confidentiality): In many application contexts, it should be impossi-
ble, or at least extremely hard, to guess instance identifiers; however, the effort
to create unique identifiers that cannot be spoofed must be justified. Testers,
support staff, and other stakeholders of an API Description may want to be
able to understand, and possibly even memorize, identifiers even if they qualify
as sensitive information that has to be protected.
One could always embed all related payload data as Embedded Entities, thus
avoiding the need to introduce identifiers referencing information that is not
included. But this simple solution wastes processing and communication resources if
information is transferred that receivers do not require. The construction of a com-
plex, partially redundant payload can also be error-prone.
How It Works
Decide on the naming scheme to be used in the API, and document it in the API
Description. Following are popular approaches to unique identification:
Instances of the Id Element pattern often travel as Atomic Parameters; they may
also become entries in Atomic Parameter Lists or leaves of Parameter Trees. The
API Description specifies the scope of the Id Element (locally vs. globally unique?)
and the lifetime of the uniqueness guarantee. Figure 6.5 shows that Id Elements are
special types of Data Elements. URIs and URNs as two types of human-readable
strings appear in the figure.
Element Stereotypes
«Pattern»
Id Element
Figure 6.5 ID ELEMENTS come in different forms: UUID, URI, URN, Surrogate Key
274 Chapter 6 Design Request and Response Message Representations
Note that identifiers can be made both human- and machine-readable. If identi-
fiers have to be entered by users at times, choose a scheme that creates short names
that are easy to pronounce. For instance, see the names for applications created by
the cloud provider Heroku; an example is peaceful-reaches-47689). Otherwise,
go with numeric UUIDs. The blog site Medium, for instance, uses hybrid URIs as
page identifiers; an example of a story URI is https://medium.com/olzzio/
seven-microservices-tenets-e97d6b0990a4.
If mandated by the security requirements, make sure that any exposed Id
Element—no matter whether it is a UUID, a human-readable string, or a surro-
gate key coming from the API implementation—is random and unpredictable and
that access to the identified elements is protected by an appropriate authorization
mechanism, as recommended by OWASP to prevent broken object-level authoriza-
tion [Yalon 2019].
URIs are globally unique, for instance, but can be reassigned over time (and then
link to unexpected targets, for instance, when used by older clients or when work-
ing with restored backup data). Sometimes, Unified Resource Names (URNs) are
preferred over URIs, using a hierarchical prefix:firstname:lastname syntax
according to RFC 2141 [Moats 1997]:
Example
Pagination cursors in the Twitter REST API [Twitter 2022] use Id Elements, for
instance, next_cursor:
{
"data": [...],
"next_cursor": "c-3yvu1pzhd3i7",
"request": {...}
}
Discussion
Id Elements such as UUIDs and URNs provide a good balance between being short
and easy to process but also expressive enough to identify members of a large entity
population and guarantee secure and reliable uniqueness in distributed systems (if
constructed and managed correctly). The implementation of the ID generation algo-
rithm determines how accurate they are.
Local identifiers are straightforward to create. Plain string identifiers are easy
for humans to process and compare, for example, when debugging. UUIDs are
hard to remember and process manually but still are easier to handle than hashed
or generated content such as access tokens that may be hundreds of characters
long. Using plain and primitive string literals as identifiers is usually not future-
proof; systems and system integrations come, change, and go over time. The less
expressive names are, the more likely it is that similar or identical names are used
elsewhere.
A simplistic approach would be to use auto-incrementing numbers such as
sid001, sid002, and so on. But there are several problems with this. Besides leaking
information, it is unnecessarily hard to keep these numbers unique in distributed set-
tings (which introduce security threats, discussed later).
Ideally, all identifiers of a certain kind spread across a distributed system should
share the same structure or naming scheme; end-to-end monitoring and event cor-
relation during root cause analyses in incident management are simplified this way.
Still, sometimes it is preferable (or unavoidable) to switch the scheme for different
entities (for instance, when legacy system constraints come into play). This is an
instance of a common conflict: flexibility versus simplicity.
UUIDs alone may not be suitable in all cases. UUID generation is implementation-
dependent and varies between libraries and programming languages. Although they
usually are 128-bits long (according to RFC 4122), some implementations follow a
somewhat predictable pattern, making it possible for brute force attackers to guess
them. It depends on the project context and requirements whether such “guessabil-
ity” is a problem. Id Elements must be included in any security analysis and design
activities such as threat modeling, security and compliance by design, penetration
testing, and compliance audits [Julisch 2011].
When multiple systems and components are integrated to realize the API, it is
hard to guarantee the uniqueness of surrogate keys from lower logical layers (such
as the database implementation) that become API-level Id Elements. Security
concerns also arise. Furthermore, the database keys of the corresponding entities
are not allowed to change in this case, even when recovering the database from a
backup. Implementation-level surrogate keys couple every consumer tightly to the
database.
276 Chapter 6 Design Request and Response Message Representations
Related Patterns
An Id Element can travel as an Atomic Parameter and be contained in Parameter
Trees. API Keys and Version Identifiers can be seen as particular kinds of identifi-
ers. Master Data Holders often require robust identification schemes because of
their longevity; Operational Data Holders typically are identified uniquely as well.
The data elements returned by Reference Data Holders may serve as Id Elements,
for instance, zip codes identifying cities (or parts of them). Link Lookup Resources
may expect Id Elements in requests and deliver Link Elements in responses; Data
Transfer Resources use locally or globally unique Id Elements to define the transfer
units or storage locations; examples of such design can be found in cloud storage offer-
ings such as AWS Simple Storage Service (S3) with its URI-identified buckets.
Local identifiers are not sufficient to implement REST fully (up to maturity level
3). If plain or structured global identifiers turn out to be insufficient, one can switch
to using absolute URIs, as described in the Link Element pattern. Link Elements
make remote reference to API elements not only globally unique but also network
accessible; they often are used to realize Linked Information Holders.
A “Correlation Identifier” and a “Return Address” and the keys used in the
“Claim Check” and the “Format Identifier” patterns [Hohpe 2003] are related pat-
terns. Creating unique identifiers is also required when applying these patterns (that
have a different usage context).
More Information
“Quick Guide to GUIDs” [GUID 2022] provides a deeper discussion of GUIDs,
including their pros and cons.
The distributed systems literature discusses general naming, identification, and
addressing approaches (for instance, [Tanenbaum 2007]). RFC 4122 [Leach 2005]
describes the basic algorithm for random number generation. XML namespaces
and Java package names are hierarchal, globally unique identification concepts
[Zimmermann 2003].
Pattern:
Link ELEmEnt
a relationship, for instance, can define the next processing step offered by a Pro-
cessing Resource or provide more details about the content of an Information
Holder Resource that appears in a collection or an overview report. The address
where this next processing step can be invoked must be specified somewhere; a mere
Id Element is not sufficient.4
How can API endpoints and operations be referenced in request and response
message payloads so that they can be called remotely?
More specifically:
The requirements here are similar to those for the sibling pattern Id Element;
endpoint and operation identification should be unique, easy to create and read, sta-
ble, and secure. The remoting context of this pattern makes it necessary to deal with
broken links and network failures.
One could use simple Id Elements to identify related remote resources/entities, but
additional processing is required to turn these identifiers into network addresses on the
Web. Id Elements are managed in the context of the API endpoint implementation
that assigns them. For local Id Elements to be used as pointers to other API endpoints,
they would have to be combined with the unique network address of the endpoint.
How It Works
4. Such pointers are required to implement the REST principle of Hypertext as the Engine of Application
State (HATEOAS) [Allamaraju 2010] with “Hypermedia Controls” [Webber 2010; Amundsen 2011].
Pagination of query response results delivered by Retrieval Operations requires such control links too.
278 Chapter 6 Design Request and Response Message Representations
When realizing HTTP resource APIs on REST maturity level 3, add metadata as
needed to support hypermedia controls, for instance, the HTTP verb and MIME
type that is supported (and expected) by the link target resource.
The instances of the Link Element pattern may travel as Atomic Parameters;
they may also become entries in Atomic Parameter Lists or leaves of Parameter
Trees. Figure 6.6 illustrates the solution on a conceptual level, featuring HTTP URI
as a prominent technology-level installment.
Element Stereotypes
- linkTarget: Location
- relationType: String
URI Parameter
- path: String
- queryParams: NameValuePairs
- altText: String
- method: HTTPVerb
The links should contain not only an address (such as a URL in RESTful HTTP)
but also information about the semantics and consequences of following the link in
a subsequent API call:
• Does the Link Elements indicate a next possible or required processing step,
for instance, in a long-running business process?
• Does it allow undoing and/or compensating a previous action?
• Does the link point at the next slice of a result set (such as a page in Pagination)?
• Does the link provide access to detailed information about a particular item?
• Or does it allow to switch to “something completely different”?5
5. https://en.wikipedia.org/wiki/And_Now_for_Something_Completely_Different.
Element Stereotypes 279
Answering the preceding questions, semantic link types typically include the
following:
1. Next: Next processing step when an incremental service type (for example, a
Processing Resource) is used.
2. Undo: Undo or compensation operation in the current context.
3. More: The address to retrieve more results. This can also be seen as making a
horizontal move in result data.
4. Details: Further information about the link source. Following this link per-
forms a vertical move in the data.
Some link types have been registered and therefore standardized somewhat. See,
for instance, the Internet Assigned Numbers Authority’s collection of link relation
types [IANA 2020] and Design and Build Great Web APIs: Robust, Reliable, and
Resilient by Mike Amundsen [Amundsen 2020].
Application-Level Profile Semantics (ALPS) [Amundsen 2021] can be used to
define Web links. Siren [Swiber 2017], another hypermedia specification for repre-
senting entities, implements the pattern in JSON. Here is the example given in the
Siren repository:
{
"links":[
{
"rel":[
"self"
],
"href":"http://api.x.io/orders/42"
}
]
}
Example
A paginated response from the Lakeside Mutual Customer Core API that contains
many Link Elements is shown in the following listing:
The self link in customers can be used to get more information about the cus-
tomer with the ID bunlo9vk5f, the address.change affords a way to change the
customer address, and the self and next links at the end point at the current and
next pagination chunk with offsets 0 and 1 respectively.
Discussion
Link Elements such as URIs are accurate. When structured nicely, URIs are human-
and machine-readable; complex URI schemas are hard to maintain. A solution- or
organization-wide URI scheme can promote consistency and ease of use. Using
standardized link types such as those defined by IANA improves maintainability, as
Element Stereotypes 281
does structuring Link Elements according to the “Web Linking” RFC 8288 [Not-
tingham 2017]. Using URIs exclusively for resource identification is a REST princi-
ple. Global addressability is achieved with decentralized naming.
The pattern solves the “global, timeless, and absolute” identification problem
at the cost of a more complicated client-side programming model (which in turn is
very flexible). Designing stable, secure URIs is nontrivial from a risk and effort point
of view. Link Elements such as URIs introduce security threats, therefore the URIs
must be included in the security design and testing efforts to ensure that invalid URIs
do not crash the server or become entry doors for attackers.
The REST style as such does not distinguish between an Id Element and a Link
Element. This has advantages (supposed ease of use and guaranteed addressabil-
ity), but also drawbacks (it is hard to change URLs). Once URIs have been used in
Link Elements, it becomes very risky and costly to change the URI scheme (the Link
Lookup Resource pattern and HTTP redirects may come to the rescue). Humans
browsing the Web can derive link information from the currently displayed HTML
page and their intuition about the provided service (or consult the service documen-
tation); API client programs and their developers cannot do this as easily.
Knowing the Link Element is not enough to interact with a remote endpoint
(such as a resource in RESTful HTTP or a SOAP operation); in addition, details
about the endpoint are required to communicate successfully (for example, in REST-
ful HTTP, the HTTP verb, the request parameters, and the structure of the response
body). To ease the communication of the additional details, these details should be
defined in the API Description of the service linked to by the Link Element and/or
included in Metadata Elements at runtime.
Related Patterns
Id Element is a related pattern, providing uniqueness of local references to API ele-
ments. Id Elements do not contain network-accessible and therefore globally unique
addresses. Id Elements typically also do not contain semantic type information, as
we suggest including in Link Elements. Both Link Elements and Id Elements can
be accompanied by Metadata Elements.
Link Elements are often used to realize Pagination. They can also organize
hypermedia-driven state transfers. Either locally valid Id Elements or full, globally
valid Link Elements might be returned by State Creation Operations and State
Transition Operations. Using Link Elements can be beneficial (or imperative)
when realizing distributed business processes as an orchestrated set of State Transi-
tion Operations exposed by one or more Processing Resources (such advanced
use was discussed as frontend BPM and BPM services in Chapter 5, “Define End-
point Types and Operations”).
282 Chapter 6 Design Request and Response Message Representations
“Linked Service” [Daigneau 2011] captures a related concept, the target of the
Link Element. A Pattern Language for RESTful Conversations [Pautasso 2016] fea-
tures related patterns for RESTful integration such as “Client-side Navigation fol-
lowing Hyperlinks,” “Long Running Request,” and “Resource Collection Traversal.”
More Information
“Designing & Implementing Hypermedia APIs” [Amundsen 2013], a QCon presen-
tation, is a good starting point for investigation. Many examples can be found in the
GitHub repositories of the API Academy [API Academy 2022].
Chapter 5 in the RESTful Web Services Cookbook presents eight recipes for “Web
Linking” [Allamaraju 2010]. For instance, Section 5.4 discusses how to assign link
relation types. Chapter 4 in the same book advises on how to design URIs. Also see
Chapter 12 of Build APIs You Won’t Hate [Sturgeon 2016b] for Link Elements in
HTTP resource APIs on maturity level 3.
The ALPS specification also deals with link representations. It is described, for
instance, in Design and Build Great Web APIs [Amundsen 2020]. RFC 6906 is about
the “profile” link relation type” [Wilde 2013]. Another draft RFC, called JSON
Hypertext Application Language, suggests a media type for link relations. The REST
Level 3 Web site [Bishop 2021] suggests profiles and patterns to realize HTTP Link
ELements.
Libraries and notations that implement the concept include HAL, Hydra [Lan-
thaler 2021], JSON-LD, Collection+JSON, and Siren; see Kai Tödter’s presentation,
“RESTful Hypermedia APIs” [Tödter 2018], and Kevin Sookocheff’s blog post for an
overview [Sookocheff 2014].
Special-Purpose Representations
Some element stereotypes are so prevalent in APIs and/or so multifaceted that they
warrant their own pattern. One example is the API Key, which is a mere atomic
Metadata Element from a message representation perspective; however, its appli-
cation in the security context adds unique forces that must be addressed. Both Error
Report and Context Representation comprise one or more representation ele-
ments. Another common trait of the three patterns in this section is a focus on API
quality (continued and intensified in the next chapter).
You might be wondering why we touch on security considerations in a chapter on
message representation design. We do not aim to provide a complete picture, but we
feature API Keys because they are widely known and used in various APIs. Security
is a broad and important topic, and usually, more sophisticated security designs than
mere API Keys are required. We provide pointers to related information in the sum-
mary section that ends this chapter.
Special-Purpose Representations 283
Pattern:
aPi kEy
How can an API provider identify and authenticate clients and their requests?
When identifying and authenticating clients on the API provider side, many ques-
tions arise:
• How can client programs identify themselves at an API endpoint without hav-
ing to store and transmit user account credentials?
• How can the identity of an API client program be made independent of the cli-
ent’s organization and program users?
• How can varying levels of API authentication, depending on security critical-
ity, be implemented?
• How can clients be identified and authenticated at an API endpoint while still
keeping the API easy to use for clients?
• How can endpoints be secured while minimizing performance impacts?
For example, the Twitter API offers an API endpoint to update the user status—
which means sending a tweet. Only identified and authenticated users should be able
to do that, and only for their own accounts.
• Access control: Let customers control which API clients can access the service.
Not all API clients might need the same permissions, so it should be possible to
manage these in a fine-grained way.
• Avoiding the need to store or transmit user account credentials: An API cli-
ent could simply send the credentials (for example, a user identifier and pass-
word) for its user account with each request (for example, via basic HTTP
authentication).6 However, these credentials are used not only for the API but
also for account management, for example, to change the payment details.
Sending these sensitive credentials through a nonencrypted channel or storing
the credentials on a server as part of the API configuration introduces a signifi-
cant security risk. A successful attack is much more severe if the attacker also
gains access to the client’s account and, as a consequence, to billing records or
other user-related information.
• Decoupling clients from their organization: External attacks can be a major
threat. Using the customer’s account credentials as an API security means
would also give internal staff (such as system administrators and API develop-
ers) full account access, which is not needed. A solution should allow distin-
guishing between the personnel who administrate and pay for an account from
the development and operations teams that configure the client programs.
• Security versus ease of use: An API provider wants to make it easy for its cus-
tomers to access its service and get up to speed quickly. Forcing a complex and
possibly onerous authentication scheme (for example, SAML,7 which provides
powerful authentication functionality) on its clients might discourage them
from using the API. Finding the right balance highly depends on the security
requirements of the API.
• Performance: Securing an API can have an impact on the performance of the
infrastructure—encrypting requests requires computing, and the date vol-
umes increase with any additional payload transmitted for authentication and
authorization purposes.
6. Basic HTTP Authentication, described in RFC 7617 [Reschke 2015], is an “authentication scheme,
which transmits credentials as user-id/password pairs, encoded using Base64.”
7. SAML, the Security Assertion Markup Language [OASIS 2005], is an OASIS standard for parties to
exchange authentication and authorization information. One application of SAML is implementing
single sign-on.
Special-Purpose Representations 285
How It Works
As an API provider, assign each client a unique token—the API Key—that the
client can present to the API endpoint for identification purposes.
Encode the API Key as an Atomic Parameter, that is, a single plain string. This
interoperable representation makes it easy to send the key in the request header, in
the request body, or as part of a URL query string.8 Because of its small size, includ-
ing it in every request causes only minimal overhead. Figure 6.7 shows an example of
a request to a protected API that includes the API Key b318ad736c6c844b in the
Authorization header of HTTP.
GET /secret
Authorization: Bearer b318ad736c6c844b
Authenticated Response
Figure 6.7 API KEY example: HTTP GET with Bearer authentication
8. For security reasons, sending a key in a URL query string is not recommended and should be used only
as a last resort. Query strings often show up in log files or analytics tools, compromising the security of
the API Key.
286 Chapter 6 Design Request and Response Message Representations
As the API provider, make sure that the generated API Keys are unique and hard
to guess. This can be achieved by using a serial number (to guarantee uniqueness)
padded by random data and signed and/or encrypted with a private key (to prevent
guessing). Alternatively, base the key on a UUID [Leach 2005]. UUIDs are easier
to use in a distributed setting because there is no serial number to be synchronized
across systems. However, UUIDs are not necessarily randomized;9 hence, they also
require further obfuscation just like in the serial number scheme.
An API Key can also be combined with an additional secret key to ensure the
integrity of requests. The secret key is shared between the client and the server but
never transmitted in API requests. The client uses this key to create a signature hash
of the request and sends the hash along with the API Key. The provider can iden-
tify the client with the provided API Key, calculate the same signature hash using
the shared secret key, and compare the two. This ensures that the request was not
tampered with. For instance, Amazon uses such asymmetric cryptography to secure
access to its Elastic Compute Cloud.
Example
The following call to a Processing Resource in the Cloud Convert API initiates the
conversion of a.docx file from Microsoft Word into PDF. The client creates a new
conversion process by informing the provider of the desired input and output format
in a State Creation Operation. These formats are passed as two Atomic Parame-
ters in the body of the request; the input file then has to be provided by a second call
to a State Transition Operation in the same API:
For billing purposes, the client identifies itself by passing the API Key gqmbw-
wB74tToo4YOPEsev5 in the Authorization header of the request, according
to the HTTP/1.1 Authentication RFC 7235 specification [Fielding 2014b]. HTTP
9. Version 1 UUIDs are a combination of timestamp and hardware addresses. The “Security Consid-
erations” section in RFC 4122 [Leach 2005] warns: “Do not assume that UUIDs are hard to guess;
they should not be used as security capabilities (identifiers whose mere possession grants access), for
example.”
Special-Purpose Representations 287
supports various types of authentication; here the RFC 6750 [Jones 2012] Bearer
type is used. The API provider can thus identify the client and charge their account.
The response contains an Id Element to represent the specific process, which can
then be used to retrieve the converted file.
Discussion
An API Key is a lightweight alternative to a full-fledged authentication protocol and
balances basic security requirements with the desire to minimize management and
communication overhead.
Having the API Key as a shared secret between the API endpoint and the client, the
endpoint can identify the client making the call and use this information to further
authenticate and authorize the client. Using a separate API Key instead of the custom-
er’s account credentials decouples different customer roles, such as administration,
business management, and API usage, from each other. This makes it possible to let the
customer create and manage multiple API Keys, for example, to be used in different
client implementations or locations, with varying permissions associated with them.
In the case of a security break or leak, they can also be revoked and a new one gener-
ated independently of the client account. A provider might also give clients the option
to use multiple API Keys with different permissions or provide analytics (for example,
the number of API calls performed) and Rate Limits per API Key. Because the API
Key is small, it can be included in each request without impacting performance much.
The API Key is a shared secret, and because it is transported with each request,
it should be used only over a secure connection such as HTTPS. If this is not possi-
ble, additional security measures (VPN, public-key cryptography) have to be used to
protect it and to satisfy the overall security requirements (such as confidentiality and
nonrepudiation). Configuring and using secure protocols and other security mea-
sures has a certain configuration management and performance overhead.
An API Key is just a simple identifier that cannot be used to transport additional
data or metadata elements such as an expiration time or authorization tokens.
Even when combined with a secret key, API Keys might be insufficient or imprac-
tical as the sole means of authentication and authorization. API Keys are also not
meant to authenticate and authorize users of the application. Consider the case
where three parties are involved in a conversation: the user, the service provider, and
a third party that wants to interact with the service provider on behalf of the user.
For example, a user might want to allow a mobile app to store its data on the user’s
Dropbox account. In this case, API Keys cannot be used if the user does not want to
share them with the third party. One should consider using OAuth 2.0 [Hardt 2012]
and OpenID Connect [OpenID 2021] instead in this (and many other) scenarios.
More secure alternatives to API Keys are full-fledged authentication or authoriza-
tion protocols, where authorization protocols include authentication functionality.
288 Chapter 6 Design Request and Response Message Representations
Kerberos [Neuman 2005] is an authentication protocol that is often used inside a net-
work to provide single sign-on. Combined with Lightweight Directory Access Proto-
col (LDAP) [Sermersheim 2006], it can also provide authorization. LDAP itself offers
authorization as well as authentication capabilities. Other examples of point-to-
point authentication protocols are Challenge-Handshake Authentication Protocol
(CHAP) [Simpson 1996] and Extensible Authentication Protocol (EAP) [Vollbrecht
2004]. We come back to this discussion in the chapter summary.
Related Patterns
Many Web servers use session identifiers [Fowler 2002] to maintain and track user ses-
sions across multiple requests; the concept is similar to that of API Keys. In contrast to
API Keys, session identifiers are used for only a single session and then discarded.
Security Patterns [Schumacher 2006] provides solutions satisfying security
requirements such as CIA and discusses their strengths and weaknesses in detail.
Access control mechanisms such as role-based access control (RBAC) and attribute-
based access control (ABAC) can complement API Keys and other approaches to
authentication. These access control practices require one of the described authenti-
cation mechanisms to be in place.
More Information
The OWASP API Security Project [Yalon 2019] and “REST Security Cheat Sheet”
[OWASP 2021] should be consulted when securing HTTP resource APIs. The cheat
sheet contains a section on API Keys and contains other valuable information on
security as well.
Chapter 15 in Principles of Web API Design addresses ways to protect APIs [Hig-
ginbotham 2021]. Chapter 12 of the RESTful Web Services Cookbook [Allamaraju
2010] is dedicated to security and presents six related recipes. “A Pattern Language
for RESTful Conversations” [Pautasso 2016] covers two related patterns of alterna-
tive authentication mechanism in a RESTful context, “Basic Resource Authentica-
tion” and “Form-Based Resource Authentication.”
Pattern:
Error rEPort
application state, missing access rights, or numerous other problems that could be the
fault of the client, the provider and its backend implementation, or the underlying
communications infrastructure (including the network and intermediaries).
How can an API provider inform its clients about communication and process-
ing faults? How can this information be made independent of the underlying
communication technologies and platforms (for example, protocol-level head-
ers representing status codes)?
10. When did you last see a SQL exception with full server-side stack trace in a Web page?
290 Chapter 6 Design Request and Response Message Representations
How It Works
Reply with error codes in response messages that indicate and classify the faults
in a simple, machine-readable way. In addition, add textual descriptions of the
errors for the API client stakeholders, including developers and/or human users
such as administrators.
Figure 6.8 ERROR REPORT pattern, providing machine- and human-readable information,
including provenance metadata
Special-Purpose Representations 291
Example
Customers logging in to their Lakeside Mutual accounts have to provide their user-
name and password:
curl -i -X POST \
--header 'Content-Type: application/json' \
--data '{"username":"xyz","password":"wrong"}' \
http://localhost:8080/auth
If the credentials are not correct, an HTTP 401 error is returned along with a
more detailed response rendered as a JSON object, both assembled by the Spring
framework in this example (the status code is repeated and explained with two texts):
HTTP/1.1 401
Content-Type: application/json;charset=UTF-8
Date: Wed, 20 Jun 2018 08:25:10 GMT
{
"timestamp": "2018-06-20T08:25:10.212+0000",
"status": 401,
"error": "Unauthorized",
"message": "Access Denied",
"path": "/auth"
}
Similarly, consider the client does not specify the content type of the request body:
Then the provider will answer with an appropriate error message (again using the
Spring defaults):
HTTP/1.1 415
EHDate: Wed, 20 Jun 2018 08:29:09 GMT
{
"timestamp": "2018-06-20T08:29:09.452+0000",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type
'application/x-www-form-urlencoded;
charset=UTF-8' not supported",
"path": "/auth"
}
292 Chapter 6 Design Request and Response Message Representations
The message tells the developer that the (default) content type of
application/x-www-form-urlencoded is not supported by this endpoint. The
Spring framework allows customizing the default error reporting.
Discussion
An Error Report that contains a code allows the API consumer to handle the error
programmatically and to present a human-readable message to the end user. By
including a textual error message, the error can be explained in more detail than with
a protocol- or transport-level code. An elaborate Error Report response can also
contain hints to solve the problem that led to the error, following the conventions
from first aid/emergency (911) calls: what happened to whom, where, and when.
Compared to a simple numeric error code, a detailed textual message is at a
higher risk to expose provider-side implementation details or other sensitive data
accidentally. For example, when informing about a failed login attempt, such a mes-
sage should not reveal whether the used user ID (for example, an email) actually
maps to an account or not, in order to make brute force attacks harder. The textual
error message might also have to be internationalized if it can reach a human user.
Explicit error reporting leads to better maintainability and evolvability, and the
more it explains errors and thus reduces the effort in the task of finding the cause
of a defect, the more effective it is; thus, the Error Report pattern is more effective
in this regard than simple protocol-level error codes. Error Report also has bet-
ter interoperability and portability properties, as it promotes protocol, format, and
platform autonomy. However, the more elaborate error messages can reveal informa-
tion that is sensitive with regard to security; such revealing of detailed information
about system internals opens up attack vectors.
Transport-level codes can still be used in addition to the payload Error Reports
that aim at becoming independent of the transport protocol. Payload Error Reports
can describe a finer-grained set of errors than possible with a predefined set of
transport-level error categories; reporting communication problems with transport-
level codes and application/endpoint processing problems in the payload is in line
with the general separation of concerns principle.
If the API is capable of responding with an internationalized message, it might
be tempting to leave out the error code. But this forces any nonhuman consumer
to parse the error message to find out what went wrong; therefore, an error report
should always include error codes that are easily machine-readable. Furthermore,
this ensures that the client developer can change messages presented to human
users.
When reporting errors that occurred when processing a Request Bundle, it is
desirable to report the error status or success both per entry in the bundle and for
Special-Purpose Representations 293
the entire bundle. Different options exist; for instance, the error report for an entire
request batch can be combined with an associative array of individual error reports
that are accessible via a request ID.
Related Patterns
An Error Report can be part of the Context Representation in response mes-
sages. It may contain Metadata Elements, for instance, those that inform about
next possible steps (to work around the reported problem or to correct it).
The “Remoting Error” pattern [Voelter 2004] contains a generalized and more low-
level notion of this pattern, focused on the viewpoint of distributed system middleware.
Error reporting is an important building block in making API implementations
robust and resilient. Many more patterns are required for a full solution, for instance,
“Circuit Breakers,” first described in [Nygard 2018a]. The systems management cat-
egory [Hohpe 2003] contains related patterns such as “Dead Letter Channel.”
More Information
See Chapter 4 of Build APIs You Won’t Hate [Sturgeon 2016b] for detailed coverage
of error reporting in the context of RESTful HTTP.
Production readiness in general is covered in Production-Ready Microservices:
Building Standardized Systems across an Engineering Organization [Fowler 2016].
RFC 7807 proposes a standard format for machine-readable error details for
HTTP APIs. In addition to using the HTTP status code, the response body contains an
Atomic Parameter List providing information about the type of error that occurred
(in the form of an URI), a title describing the problem category and a detail element
with a more elaborate problem description that includes data of the request.
Pattern:
CONTEXT REPRESENTATION
How can API consumers and providers exchange context information without
relying on any particular remoting protocols?
294 Chapter 6 Design Request and Response Message Representations
11. Despite the notion of “full stack developers,” which is often mentioned today.
296 Chapter 6 Design Request and Response Message Representations
How It Works
Combine and group all Metadata Elements that carry the desired informa-
tion into a custom representation element in request and/or response messages.
Do not transport this single Context Representation in protocol headers,
but place it in the message payload.
Separate global from local context in a conversation by structuring the Con-
text Representation accordingly. Position and mark the consolidated Context
Representation element so that it is easy to find and distinguish from other
Data Elements.
«Domain Class»
Message
- protocolHeaders
- otherPayload - otherPayload
requestContext responseContext
«Pattern»
Context Representation
- clientInformation
- securityCredentials
- qualityOfServiceProperties
- desiredResponseFormat
For instance, a microservice might be invoked that calls another service, which pos-
sibly calls yet another one. A deep hierarchy makes it difficult to achieve end-to-end
reliability, understandability, and performance—especially when the calls are syn-
chronous. In other scenarios, services may have to be called in a particular order, for
instance, to realize complex business processes or login procedures (such as fetch-
ing an authorization token before a business operation can be called). In both cases,
it is necessary to carry context information over to the following API calls. For
example, a user credential (or token) might have to be passed on after its creation.
298 Chapter 6 Design Request and Response Message Representations
The business process identifier (ID) or the original transaction might have to be dele-
gated to services deeper in the call hierarchy to guarantee correct request authorization.
Tracing and logging throughout a conversation benefits from such context handover.
Figure 6.10 visualizes operation call nesting.
Call Sequence
Request
Multi-Request Transaction
Originating Provider/
Business Process/
Provider
Client Client
Provider
Figure 6.10 An API provider also acting as API client, requiring context information
Transaction ID
Message ID
Related Request/Response Scope: Message Payload
Message ID Quality of
Service (QoS)
including
Time to Live
Pagination
(Control Metadata)
Domain Data
(Published Language)
QoS
(Max. Duration)
Figure 6.11 Scopes for context: Global (conversation) and local (operation, request/response)
Example
The following service contract sketch introduces a custom Context Representa-
tion called RequestContext in the payload of the request message of the
getCustomerAttributes operation. It is decorated with the stereotype
<<Context_Representation>> and therefore easily recognizable in the request
payload. The API contract notation used in the example is Microservice
Domain-Specific Language (MDSL). An MDSL primer and reference is presented in
Appendix C:
operation getCustomerAttributes
expecting payload {
<<Context_Representation>> {
"requestContextSharedByAllOperations": RequestContext,
<<Wish_List>>"desiredCustomerAttributes":ID<string>+
},
<<Data_Element>> "searchParameters":D<string>*
}
delivering payload {
<<Context_Representation>> {
<<Metadata_Element>> {
"billingInfo": D<int>,
"moreAnalytics":D},
<<Error_Report>> {
"errorCode":D<int>,
"errorMessage":D<string>}
}, {
<<Pagination>> {
"thisPageContent":CustomerDTO*,
"previousPage":ID?,
"nextPage":ID?}
}
}
openapi: 3.0.1
info:
title: ContextRepresentationExample
version: "1.0"
servers: []
tags:
- name: CustomerInformationHolderService
externalDocs:
description: The role of this endpoint is not specified.
url: ""
Special-Purpose Representations 301
paths:
/CustomerInformationHolderService:
post:
tags:
- CustomerInformationHolderService
summary: POST
description: POST
operationId: getCustomerAttributes
requestBody:
content:
application/json:
schema:
type: object
properties:
anonymous1:
type: object
properties:
requestContextSharedByAllOperations:
$ref:'#/components/schemas/RequestContext'
desiredCustomerAttributes:
minItems: 1
type: array
items:
type: string
searchParameters:
type: array
items:
type: string
responses:
"200":
description: getCustomerAttributes successful
execution
content:
application/json:
schema:
type: object
properties:
anonymous2:
type: object
properties:
anonymous3:
type: object
properties:
302 Chapter 6 Design Request and Response Message Representations
billingInfo:
type: integer
format: int32
moreAnalytics:
type: string
anonymous4:
type: object
properties:
errorCode:
type: integer
format: int32
errorMessage:
type: string
anonymous5:
type: object
properties:
anonymous6:
type: object
properties:
thisPageContent:
type: array
items:
$ref: "#/components\
/schemas/CustomerDTO"
previousPage:
type: string
format: uuid
nullable: true
nextPage:
type: string
format: uuid
nullable: true
components:
schemas:
KeyValuePair:
type: object
CustomerDTO:
type: object
RequestContext:
type: object
properties:
apiKey:
type: string
Special-Purpose Representations 303
sessionId:
type: integer
format: int32
nullable: true
qosPropertiesThatShouldNotGoToProtocolHeader:
type: array
items:
$ref: '#/components/schemas/KeyValuePair'
The MDSL specification is much shorter than the OpenAPI one generated from
it.
Discussion
Use of this pattern not only promotes context Metadata Elements from protocol
headers into payloads but does so in a non-scattered way. The information in the
Context Representation may deal with runtime QoS such as priority classifiers;
control metadata and provenance metadata often are included in Context Repre-
sentations appearing in request messages. Exchanging aggregated metadata such as
result counts in responses is also possible but is less common.
By representing control information and other metadata in a common form as
part of the payload, API client and provider can be isolated/abstracted from changes
in the underlying protocol or technology used (for instance, if different protocols
such as plain HTTP, AMQP, WebSockets, or gRPC are used). A dependency on
a single protocol header format (and protocol support for it) is avoided. A single
request traveling through a gateway or proxy could be switched from one protocol to
another and therefore lose or modify its original protocol header information along
the way. For example, the gRPC-Gateway project [gRPC-Gateway 2022] generates a
reverse-proxy server that translates a RESTful JSON API into gRPC; HTTP head-
ers are mapped to gRPC request headers by the proxy. Regardless of such a protocol
switch, header information in the payload stays the same and reaches the client.
The introduction of a shared/standardized Context Representation pays off
if the information needs of clients and consumers are similar or identical across the
entire endpoint or API. If an API is served by only a single transport protocol, an
explicit, custom Context Representation leads to one-time-only design and also
processing effort; it might be easier to stay with the native, protocol-level way of
transmitting the context (such as HTTP headers). Protocol purists may perceive the
introduction of custom headers in the payload as an antipattern that indicates a lack
of understanding of the protocol and its capabilities. This discussion comes down to
the relative priorities of conformance with technical recommendations versus con-
trol of one’s API destiny.
304 Chapter 6 Design Request and Response Message Representations
Related Patterns
This pattern is often combined with other patterns; for instance, the data requests
expressed in a Wish List can be part of Context Representations (but do not neces-
sarily have to be). Similarly, an Error Report can find its place in response message
contexts. Request Bundles might require two types of Context Representation,
one on the container level and one for each individual request or response element. For
instance, both individual Error Reports and an aggregated bundle-level report might
make sense when one or more individual responses in a Request Bundles fail. A Ver-
sion Identifier can be transported in the Context Representation as well.
Summary 305
While the “Front Door” pattern [Schumacher 2006] is applied frequently to intro-
duce reverse proxies, API providers and clients might not want all headers to go
through the security procedures provided by such proxies; Context Representa-
tion can be applied in such cases. An “API Gateway” [Richardson 2016] or proxy
could act as an intermediary and modify the original request(s) and response(s), but
this makes the overall architecture more complex and more challenging to manage
and evolve. While this approach might be convenient, it also means giving up control
(or having less control, but an extra dependency).
A similar pattern appears in several other pattern languages. For instance, the
“Context Object” [Alur 2013] solves the problem of protocol-independent storage
of state and system information in a Java programming context (rather than in a
remoting context). The “Invocation Context” pattern [Voelter 2004] describes a
solution for bundling contextual information in an extensible invocation context of
a distributed invocation.
An Invocation Context is transferred between a client and remote object with every
remote invocation. The “Envelope Wrapper” pattern [Hohpe 2003] solves a similar
problem, making certain parts of a message visible to the messaging infrastructure
responsible for a particular leg. Systems management patterns such as “Wire Tap”
[Hohpe 2003] can be used to implement the required auditing and logging.
More Information
Chapter 3 in the RESTful Web Services Cookbook discusses an alternative approach
based on entity headers (in the context of HTTP) in two of its recipes [Allamaraju
2010].
“On the Representation of Context” [Stalnaker 1996] gives an overview of con-
text representation in linguistics.
The Metadata Element pattern provides more pointers to related patterns and
other background information.
Summary
This chapter investigated the structure and meaning of representation elements in
request and response messages. Element stereotypes distinguish data from metadata,
identifiers, and links; some representation elements have special and common
purposes.
We concentrated on the data contract as represented by Data Elements. Most
data that an API contract exposes comes from the API implementation (for exam-
ple, instances of domain model entities). As data about data, Metadata Elements
306 Chapter 6 Design Request and Response Message Representations
This chapter covers seven patterns that address issues with API quality. Arguably, it
would be hard to find any API designers and product owners who do not value quali-
ties such as intuitive understandability, splendid performance, and seamless evolva-
bility. That said, any quality improvement comes at a price—a literal cost such as
extra development effort but also negative consequences such as an adverse impact
on other qualities. This balancing act is caused by the fact that some of the desired
qualities conflict with each other—just think about the almost classic performance
versus security trade-offs.
We first establish why these issues are relevant in “Introduction to API Quality.”
The next section presents two patterns dealing with “Message Granularity.” Three
patterns for “Client-Driven Message Content” follow, and two patterns aim at
“Message Exchange Optimization.”
These patterns support the third and the fourth phases of the Align-Define-
Design-Refine (ADDR) design process for APIs that we introduced at the start of
Part 2.
309
310 Chapter 7 Refine Message Design for Quality
API providers must balance conflicting concerns to guarantee a high service qual-
ity while ensuring cost-effectiveness. Hence, all patterns presented in this chapter
help resolve the following overarching design issue:
How to achieve a certain level of quality of a published API while at the same
time utilizing the available resources in a cost-effective way?
Performance and scalability concerns might not have a high priority when initially
developing a new API, especially in agile development—if they arise at all. Usually,
there is not enough information on how clients will use the API to make informed
decisions. One could also just guess, but that would not be prudent and would vio-
late principles such as making decisions in the most responsible moment [Wirfs-
Brock 2011].
Note that the preceding list is nonexhaustive. The answers to these questions
depend on the quality goals of the API stakeholders and additional concerns. The
patterns in this chapter provide different options to choose from under a given set
of requirements; adequate selections differ from API to API. Part 1 of this book
provided a decision-oriented overview of these patterns in the “Deciding for API
Quality Improvements” section of Chapter 3, “API Decision Narratives.” In this
chapter, we cover them in depth.
several options to fine-tune message contents to avoid issuing too many requests or
transmitting data that is not used; in contrast, Conditional Requests avoid send-
ing data that a client already has. While the number of messages exchanged stays the
same, the API implementation can respond with a dedicated status code to inform
the client that more recent data is not available. The number of requests sent and
responses received can also impair the quality of an API. If clients have to issue many
small requests and wait for individual responses, bundling them into a larger mes-
sage can improve throughput and reduce the client-side implementation effort. The
Request Bundle pattern presents this design option.
Figure 7.1 provides an overview of the patterns in this chapter and shows their
relations.
Number of requests
less more
Message Granularity
Information elements in request and response message representations, concepts
from our API domain model (see Chapter 1, “Application Programming Interface
(API) Fundamentals”), often reference other ones to express containment, aggrega-
tion, or other relationships. For instance, operational data such as orders and ship-
ments typically is associated with master data such as product and customer records.
To expose such references when defining API endpoints and their operations, the two
basic options are as follows:
1. Embedded Entity: Embed the referenced data in a possibly nested Data Ele-
ment (introduced in Chapter 6, “Design Request and Response Message Rep-
resentations”) in the message representation.
2. Linked Information Holder: Place a Link Element (also Chapter 6) in the
message representation to look up the referenced data via a separate API call to
an Information Holder Resource (Chapter 5, “Define Endpoint Types and
Operations”).
These message sizing and scoping options have an impact on the API quality:
• Performance and scalability: Both message size and number of calls required
to cover an entire integration scenario should be kept low. Few messages that
transport a lot of data take time to create and process; many small messages
are easy to create but cause more work for the communications infrastructure
and require receiver-side coordination.
• Modifiability and flexibility: Backward compatibility and extensibility are
desired in any distributed system whose parts evolve independently of each
other. Information elements contained in structured, self-contained represen-
tations might be hard to change because any local updates must be coordinated
and synchronized with updates to the API operations that work with them and
related data structures in the API implementation. Structured representations
that contains references to external resources usually is even harder to change
than self-contained data because clients have to be aware of such references so
that they can follow them correctly.
• Data quality: Structured master data such as customer profiles or product details
differs from simple unstructured reference data such as country and currency
codes (Chapter 5 provides a categorization of domain data by lifetime and muta-
bility). The more data is transported, the more governance is required to make
314 Chapter 7 Refine Message Design for Quality
this data useful. For instance, data ownership might differ for products and cus-
tomers in an online shop, and the respective data owners usually have different
requirements, for example, regarding data protection, data validation, and update
frequency. Extra metadata and data management procedures might be required.
• Data privacy: In terms of data privacy classifications, the source and the tar-
get of data relationships might have different protection needs; an example
is a customer record with contact address and credit card information. More
fine-grained data retrieval facilitates the enforcement of appropriate controls
and rules, lowering the risk of embedded restricted data accidentally slipping
through.
• Data freshness and consistency: If data is retrieved by competing clients at
different times, inconsistent snapshots of and views on data in these clients
might materialize. Data references (links) may help clients to retrieve the most
recent version of the referenced data. However, such references may break, as
their targets may change or disappear after the link referring to it has been
sent. By embedding all referenced data in the same message, API providers can
deliver an internally consistent snapshot of the content, avoiding the risk of
link targets becoming unavailable. Software engineering principles such as sin-
gle responsibility may lead to challenges regarding data consistency and data
integrity when taken to the extreme because data may get fragmented and
scattered.
The two message granularity patterns, Embedded Entity and Linked Informa-
tion Holder in this section address these issues in opposite ways. Combining them
on a case-by-case basis leads to adequate message sizes, balancing the number of
calls and the amount of data exchanged to meet diverse integration requirements.
Pattern:
EmbEddEd Entity
several of the related information elements when creating request messages or pro-
cessing response messages.
How can one avoid exchanging multiple messages when their receivers require
insights about multiple related information elements?
One could simply define one API endpoint for each basic information element
(for instance, an entity defined in an application domain model). This endpoint is
accessed whenever API clients require data from that information element, for exam-
ple, when it is referenced from another one. But if API clients use such data in many
situations, this solution causes many subsequent requests when references are fol-
lowed. This could possibly make it necessary to coordinate request execution and
introduce conversation state, which harms scalability and availability; distributed
data also is more difficult than local data to keep consistent.
How It Works
For any data relationship that the receiver wants to follow, embed a Data Ele-
ment 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.
Analyze the outgoing relationships in the new Data Element and consider
embedding them in the message as well. Repeat this analysis until transitive closure
is reached—that is, until all reachable elements have been either included or excluded
(or circles are detected and processing stopped). Review each source-target relation-
ship carefully to assess whether the target data is really needed on the receiver side
in enough cases. A yes answer to this question warrants transmitting relationship
information as Embedded Entities; otherwise, transmitting references to Linked
Information Holders might be sufficient. For instance, if a purchase order has a
uses relation to product master data and this master data is required to make sense
of the purchase order, the purchase order representation in request or response mes-
sages should contain a copy of all relevant information stored in the product master
data in an Embedded Entity.
Figure 7.2 sketches the solution.
316 Chapter 7 Refine Message Design for Quality
API
API Client
Endpoint
Datasource
API
Implementation
E1:
E1:
E2:
E2:
Request
Response
Figure 7.2 EMBEDDED ENTITY: Single API endpoint and operation, returning structured
message content that matches the structure of the source data in the API implementation to
follow data relations
causing data duplication. In that case, it might be better to express the second rela-
tionship with embedded Id Elements or Link Elements instead.
In any of these cases, the API Description has to explain the existence, structure,
and meaning of the Embedded Entity instances.
Example
Lakeside Mutual, our microservices sample application introduced in Chapter 2,
“Lakeside Mutual Case Study,” contains a service called Customer Core that
aggregates several information items (here, entities and value objects from domain-
driven design [DDD]) in its operation signatures. API clients such as the Customer
Self-Service frontend can access this data via an HTTP resource API. This API
contains several instances of the Embedded Entity pattern. Applying the pattern,
a response message might look as follows:1
{
"customer": {
"id": "gktlipwhjr"
},
"customerProfile": {
"firstname": "Robbie",
"lastname": "Davenhall",
"birthday": "1961-08-11T23:00:00.000+0000",
"currentAddress": {
"streetAddress": "1 Dunning Trail",
"postalCode": "9511",
"city": "Banga"
},
"email": "[email protected]",
"phoneNumber": "491 103 8336",
"moveHistory": [{
"streetAddress": "15 Briar Crest Center",
"postalCode": "",
"city": "Aeteke"
}]
},
"customerInteractionLog": {
"contactHistory": [],
"classification": "??"
}
}
The referenced information elements are all fully contained in the response mes-
sage; examples are customerProfile and customerInteractionLog. No URI
links to other resources appear. Note that the customerProfile entity actually
embeds nested data in this exemplary data set (for example, currentAddress and
moveHistory), while the customerInteractionLog does not (but is still included
as an empty Embedded Entity).
Discussion
Applying this pattern solves the problem of having to exchange multiple messages
when receivers require multiple related information elements. An Embedded Entity
reduces the number of calls required: if the required information is included, the cli-
ent does not have to create a follow-on request to obtain it. Embedding entities can
lead to a reduction in the number of endpoints, because no dedicated endpoint to
retrieve linked information is required. However, embedding entities leads to larger
response messages, which usually take longer to transfer and consume more band-
width. Care must also be taken to ensure that the included information does not have
higher protection needs than the source and that no restricted data slips through.
It can be challenging to anticipate what information different message receivers
(that is, API clients for response messages) require to perform their tasks. As a result,
there is a tendency to include more data than most clients need. Such design can be
found in many Public APIs serving many diverse and possibly unknown clients.
Traversing all relationships between information elements to include all possibly
interesting data may require complex message representations and lead to large mes-
sage sizes. It is unlikely and/or difficult to ensure that all recipients will require the
same message content. Once included and exposed in an API Description, it is hard
to remove an Embedded Entity in a backward-compatible manner (as clients may
have begun to rely on it).
If most or all of the data is actually used, sending many small messages might
require more bandwidth than sending one large message (for instance, because pro-
tocol header metadata is sent with each small message). If the embedded entities
change at different speeds, retransmitting them causes unnecessary overhead because
messages with partially changed content can only be cached in their entirety. A fast-
changing operational entity might refer to immutable master data, for instance.
The decision to use Embedded Entity might depend on the number of message
consumers and the homogeneity of their use cases. For example, if only one consumer
with a specific use case is targeted, it is often good to embed all required data straight
away. In contrast, different consumers or use cases might not work with the same data.
In order to minimize message sizes, it might be advisable not to transfer all data. Both
client and provider might be developed by the same organization—for example, when
providing “Backends for Frontends” [Newman 2015]. Embedding entities can be a
Message Granularity 319
reasonable strategy to minimize the number of requests in that case. In such a setting,
they simplify development by introducing a uniform regular structure.
Combinations of linking and embedding data often make sense, for instance,
embedding all data immediately displayed in a user interface and linking the rest for
retrieval upon demand. The linked data is then fetched only when the user scrolls
or opens the corresponding user interface elements. Atlassian [Atlassian 2022] dis-
cusses such a hybrid approach: “Embedded related objects are typically limited in
their fields to avoid such object graphs from becoming too deep and noisy. They
often exclude their own nested objects in an attempt to strike a balance between per-
formance and utility.”
“API Gateways” [Richardson 2016] and messaging middleware [Hohpe 2003] can
also help when dealing with different information needs. Gateways can either provide
two alternative APIs that use the same backend interface and/or collect and aggregate
information from different endpoints and operations (which makes them stateful). Mes-
saging systems may provide transformation capabilities such as filters and enrichers.
Related Patterns
Linked Information Holder describes the complementary, opposite solution for
the reference management problem. One reason for switching to the Linked Infor-
mation Holder might be to mitigate performance problems, for instance, caused by
slow or unreliable networks that make it difficult to transfer large messages. Linked
Information Holders can help to improve the situation, as they allow caching each
entity independently.
If reducing message size is the main design goal, a Wish List or, even more expres-
sive, a Wish Template can also be applied to minimize the data to be transferred by
letting consumers dynamically describe which subset of the data they need. Wish
List or Wish Template can help to fine-tune the content in an Embedded Entity.
Operational Data Holders reference Master Data Holders by definition
(either directly or indirectly); these references often are represented as Linked Infor-
mation Holders. References between data holders of the same type are more likely
to be included with the Embedded Entity pattern. Both Information Holder
Resources and Processing Resources might deal with structured data that needs
to be linked or embedded; in particular, Retrieval Operations either embed or link
related information.
More Information
Phil Sturgeon features this pattern as “Embedded Document (Nesting)” in [Sturgeon
2016b]. See Section 7.5 of Build APIs You Won’t Hate for additional advice and
examples.
320 Chapter 7 Refine Message Design for Quality
Pattern:
LinkEd information HoLdEr
How can messages be kept small even when an API deals with multiple infor-
mation elements that reference each other?
A rule of thumb for distributed system design states that exchanged messages
should be small because large messages may overutilize the network and the end-
point processing resources. However, not all of what communication participants
want to share with each other might fit into such small messages; for instance, they
might want to follow many or all of the relationships within information elements.
If relationship sources and targets are not combined into a single message, par-
ticipants have to inform each other how to locate and access the individual pieces.
This distributed information set has to be designed, implemented, and evolved; the
resulting dependencies between the participants and the information they share
have to be managed. For instance, insurance policies typically refer to customer
and product master data; each of these related information elements might, in
turn, consist of several parts (see Chapter 2 for deeper coverage of the data and
domain entities in this example).
One option is to always (transitively) include all the related information elements
of each transmitted element in request and response messages throughout the API,
as described in the Embedded Entity pattern. However, this approach can lead to
large messages containing data not required by some clients and harm the perfor-
mance of individual API calls. It couples the stakeholders of this data.
2. This pattern context is similar to that of Embedded Entity but emphasizes the diversity of client
wants and needs.
Message Granularity 321
How It Works
API
API Client 1
Endpoint 1
Datasource
API
Implementation 1
E1:
E1:
E2:
L:
API
2
Endpoint 2
API
Implementation 2
E2:
L: Link Element
Figure 7.3 LINKED INFORMATION HOLDER: Two API endpoints are involved. The first
response contains a link rather than data from the data source; the data is retrieved from it in
a follow-on request to the second endpoint
322 Chapter 7 Refine Message Design for Quality
The Link Element that constitutes the Linked Information Holder provides
location information, for instance, a URL (with domain/hostname and port number
when using HTTP over TCP/IP). The Link Element also has a local name to be able
to identify it within the message representation (such as a JSON object). If more
information about the relation should be sent to clients, this Link Element can be
annotated with details about the corresponding relationship, for instance, a Meta-
data Element specifying its type and semantics. In any case, API clients and provid-
ers must agree on the meaning of the link relationships and be aware of coupling and
side effects introduced. The existence and the meaning of the Linked Information
Holder, including cardinalities on both ends of the relation, has to be documented
in the API Description.
One-to-many relationships can be modeled as collections, for instance, by
transmitting multiple Link Elements as Atomic Parameter Lists. Many-to-many
relationships (such as that between books and their readers in a library manage-
ment system) can be modeled as two one-to-many relationships, with one collec-
tion linking the source data to the targets and a second one linking the target data
to the sources (assuming that the message recipient wants to follow the relation in
both directions). Such design may require the introduction of an additional API
endpoint, a relationship holder resource, representing the relation rather than its
source or target. This endpoint then exposes operations to retrieve all relationships
with their sources and targets; it may also allow clients to find the other end of a
relationship they already know about. Different types of Link Elements identify
these ends in messages sent to and from the relationship holder resource. Unlike
in the Embedded Entity pattern, circular dependencies in the data are less of an
issue when working with Linked Information Holders (but still should be han-
dled); the responsibility to avoid endless loops in the data processing shifts from
the message sender to the recipient.
Example
Our Lakeside Mutual sample application for Customer Management utilizes a Cus-
tomer Core service API that aggregates several information elements from the
domain model of the application, in the form of entities and value objects from
DDD. API clients can access this data through a Customer Information Holder,
implemented as a REST controller in Spring Boot.
Message Granularity 323
{
"customer": {
"id": "gktlipwhjr"
},
"links": [{
"rel": "customerProfile",
"href": "/customers/gktlipwhjr/profile"
}, {
"rel": "moveHistory",
"href": "/customers/gktlipwhjr/moveHistory"
}],
"email": "[email protected]",
"phoneNumber": "491 103 8336",
"customerInteractionLog": {
"contactHistory": [],
"classification": "??"
}
}
Discussion
Linking instead of embedding related data results in smaller messages and uses fewer
resources in the communications infrastructure when exchanging individual messages.
However, this has to be contrasted with the possibly higher resource use caused by the
extra messages required to follow the links: Additional requests are required to derefer-
ence the linked information. Linking instead of embedding might demand more
resources in the communications infrastructure. Additional Information Holder
Resource endpoints have to be provided for the linked data, causing development and
operations effort and cost, but allowing to enforce additional access restrictions.
324 Chapter 7 Refine Message Design for Quality
Related Patterns
Linked Information Holders typically reference Information Holder
Resources. The referenced Information Holder Resources can be combined
with Link Lookup Resource to cope with potentially broken links. By definition,
Operational Data Holders reference Master Data Holders; these references can
either be included and flattened as Embedded Entities or structured and then pro-
gressively followed using Linked Information Holders.
Other patterns that help reduce the amount of data exchanged can be used alter-
natively. For instance, Conditional Request, Wish List, and Wish Template are
eligible; Pagination is an option too.
More Information
“Linked Service” [Daigneau 2011] is a similar pattern but is less focused on data.
“Web Service Patterns” [Monday 2003] has a “Partial DTO Population” pattern that
solves a similar problem; DTO stands for Data Transfer Object.
See Build APIs You Won’t Hate, Section 7.4 [Sturgeon 2016b], for additional
advice and examples, to be found under “Compound Document (Sideloading).”
The backup, availability, consistency (BAC) theorem investigates data manage-
ment issues further [Pardon 2018].
• Performance, scalability, and resource use: Providing all clients with all data
every time, even to those that only have a limited or minimal information need,
comes at a price. From a performance and workload point of view, it there-
fore makes sense to transmit only the relevant parts of a data set. However,
the pre- and postprocessing required to rightsize the message exchanges also
require resources and might harm performance. These costs have to be bal-
anced against the expected reduction of the response message size and the
capabilities of the underlying transport network.
326 Chapter 7 Refine Message Design for Quality
The patterns in this section, Pagination, Wish List, and Wish Template, address
these challenges in different ways.
Client-Driven Message Content (aka Response Shaping) 327
Pattern:
Pagination
How can an API provider deliver large sequences of structured data without
overwhelming clients?
One could think of sending the entire large response data set in a single response
message, but such a simple approach might waste endpoint and network capacity;
it also does not scale well. The size of the response to a query may be unknown in
advance, or the result set may be too large to be processed at once on the client side
(or on the provider side). Without mechanisms to limit such queries, processing errors
328 Chapter 7 Refine Message Design for Quality
such as out-of-memory exceptions may occur, and the client or the endpoint imple-
mentation may crash. Developers and API designers often underestimate the memory
requirements imposed by unlimited query contracts. These problems usually go unno-
ticed until concurrent workload is placed on the system or the data set size increases. In
shared environments, it is possible that unlimited queries cannot be processed efficiently
in parallel, which leads to similar performance, scalability, and consistency issues—only
combined with concurrent requests, which are hard to debug and analyze anyway.
How It Works
Divide large response data sets into manageable and easy-to-transmit chunks
(also known as pages). Send one chunk of partial results per response message
and inform the client about the total and/or remaining number of chunks.
Provide optional filtering capabilities to allow clients to request a particu-
lar selection of results. For extra convenience, include a reference to the next
chunk/page from the current one.
The number of data elements in a chunk can be fixed (its size then is part of the
API contract) or can be specified by the client dynamically as a request parameter.
Metadata Elements and Link Elements inform the API client how to retrieve addi-
tional chunks subsequently.
API clients then process some or all partial responses iteratively as needed; they
request the result data page by page. Hence, subsequent requests for additional
chunks might have to be correlated. It might make sense to define a policy that
governs how clients can terminate the processing of the result set and the prepara-
tion of partial responses (possibly requiring session state management).
Figure 7.4 visualizes a sequence of requests that use Pagination to retrieve three
pages of data.
Variants The pattern comes in four variants that navigate the data set in different
ways: page based, offset based, cursor or token based, and time based.
Page-Based Pagination (a somewhat tautological name) and Offset-Based Pagina-
tion refer to the elements of the data set differently. The page-based variant divides
the data set into same-sized pages; the client or the provider specify the page size.
Clients then request pages by their index (like page numbers in a book). With Offset-
Based Pagination, a client selects an offset into the whole data set (that is, how many
single elements to skip) and the number of elements to return in the next chunk
(often referred to as limit). Both approaches may be used interchangeably (the offset
Client-Driven Message Content (aka Response Shaping) 329
1 API
API Client
Endpoint API
Implementation
2
PageSize = 2
PageId = 2 Datasource
Page 2: E3: E4:
E1:
Total Pages: 3
PageSize = 2 Next Page: Page 3
PageId = 3 E2:
3 E3:
E4:
Page 3: E5:
E5:
Total Pages: 3
E1: Data Element Next Page: None
Figure 7.4 PAGINATION: Query and follow-on requests for pages, response messages with
partial results
can be calculated by multiplying the page size with the page number); they address
the problem and resolve the forces in similar ways. Page-Based Pagination and
Offset-Based Pagination do not differ much with respect to developer experience and
other qualities. Whether entries are requested with an offset and limit or all entries
are divided into pages of a particular size and then requested by an index is a minor
difference. Either case requires two integer parameters.
These variants are not well suited for data that changes in between requests and
therefore invalidates the index or offset calculations. For example, given a data set
ordered by creation time from most recent to oldest, let us assume that a client has
retrieved the first page and now requests the second one. In between these requests,
the element at the front of the data set is removed, causing an element to move from
the second to the first page without the client ever seeing it.
330 Chapter 7 Refine Message Design for Quality
The Cursor-Based Pagination variant solves this problem: it does not rely on the
absolute position of an element in the data set. Instead, clients send an identifier that
the provider can use to locate a specific item in the data set, along with the number
of elements to retrieve. The resulting chunk does not change even if new elements
have been added since the last request.
The remaining fourth variant, Time-Based Pagination, is similar to Cursor-Based
Pagination but uses timestamps instead of element IDs. It is used in practice less
frequently but could be applied to scroll through a time plot by gradually requesting
older or newer data points.
Example
The Lakeside Mutual Customer Core backend API illustrates Offset-Based Pagina-
tion in its customer endpoint:
This call returns the first chunk of two entities and several control Metadata
Elements. Besides the link relation [Allamaraju 2010] that points at the next chunk,
the response also contains the corresponding offset, limit, and total size val-
ues. Note that size is not required to implement Pagination on the provider side
but allows API clients to show end users or other consumers how many more data
elements (or pages) may be requested subsequently.
{
"offset": 0,
"limit": 2,
"size": 50,
"customers": [
...
,
...
],
"_links": {
"next": {
"href": "/customers?limit=2&offset=2"
}
}
}
Client-Driven Message Content (aka Response Shaping) 331
The preceding example can easily be mapped to the corresponding SQL query
LIMIT 2 OFFSET 0. Instead of talking about offsets and limits, the API could also
use the page metaphor in its message vocabulary, as shown here:
{
"page": 0,
"pageSize": 2,
"totalPages": 25,
"customers": [
...
,
...
],
"_links": {
"next": {
"href": "/customers?page-size=2&page=1"
}
}
}
Using Cursor-Based Pagination, the client first requests an initial page of the
desired size 2:
{
"pageSize": 2,
"customers": [
...
,
...
],
"_links": {
"next": {
"href": "/customers?page-size=2&cursor=mfn834fj"
}
}
}
The response contains a link to the next chunk of data, represented by the cursor
value mfn834fj. The cursor could be as simple as the primary key of the database
or contain more information, such as a query filter.
332 Chapter 7 Refine Message Design for Quality
Discussion
Pagination aims to substantially improve resource consumption and performance
by sending only the data presently required and doing so just in time.
A single large response message might be inefficient to exchange and process. In
this context, data set size and data access profile (that is, the user needs), especially
the number of data records required to be available to an API client (immediately
and over time), require particular attention. Especially when returning data for
human consumption, not all data may be needed immediately; then Pagination has
the potential to improve the response times for data access significantly.
From a security standpoint, retrieving and encoding large data sets may incur high
effort and cost on the provider side and therefore lead to a denial-of-service attack.
Moreover, transferring large data sets across a network can lead to interruptions, as
most networks are not guaranteed to be reliable, especially cellular networks. This
aspect is improved with Pagination because attackers can only request pages with
small portions of data instead of an entire data set (assuming that the maximum
value for the page size is limited). Note that in a rather subtle attack, it could still
be enough to request the first page; if a poorly designed API implementation loads
a vast data set as a whole, expecting to feed the data to the client page by page, an
attacker still is able to fill up the server memory.
If the structure of the desired responses is not set oriented, so that a collection of
data items can be partitioned into chunks, Pagination cannot be applied. Compared
to response messages using the Parameter Tree pattern without Pagination, the
pattern is substantially more complex to understand and thus might be less conveni-
ent to use, as it turns a single call into a longer conversation. Pagination requires
more programming effort than does exchanging all data with one message.
Pagination leads to tighter coupling between API client and provider than single
message transfers because additional representation elements are required to man-
age the slicing of the result sets into chunks. This can be mitigated by standardizing
the required Metadata Elements. For example, with hypermedia, one just follows
a Web link to fetch the next page. A remaining coupling issue is the session that may
have to be established with each client while the pages are being scanned.
If API clients want to go beyond sequential access, complex parameter represen-
tations may be required to perform random access by seeking specific pages (or to
allow clients to compute the page index themselves). The Cursor-Based Pagination
variant with its—from a client perspective, opaque—cursor or token usually does
not allow random access.
Delivering one page at a time allows the API client to process a digestible amount
of data; a specification of which page to return facilitates remote navigation directly
within the data set. Less endpoint memory and network capacity are required to
handle individual pages, although some overhead is introduced because Pagination
management is required (discussed shortly).
Client-Driven Message Content (aka Response Shaping) 333
• Where, when, and how to define the page size (the number of data elements
per page). This influences the chattiness of the API (retrieving the data in many
small pages requires a large number of messages).
• How to order results—that is, how to assign them to pages and how to arrange
the partial results on these pages. This order typically cannot change after the
paginated retrieval begins. Changing the order as an API evolves over its life
cycle might make a new API version incompatible with previous ones, which
might go unnoticed if not communicated properly and tested thoroughly.
• Where and how to store intermediate results, and for how long (deletion policy,
timeouts).
• How to deal with request repetition. For instance, do the initial and the sub-
sequent requests have to be idempotent to prevent errors and inconsistencies?
• How to correlate pages/chunks (with the original, the previous, and the next
requests).
Further design issues for the API implementation include the caching policy (if
any), the liveness (currentness) of results, filtering, as well as query pre- and post-
processing (for example, aggregations, counts, sums). Typical data access layer con-
cerns (for instance, isolation level and locking in relational databases) come into play
here as well [Fowler 2002]. Consistency requirements differ by client type and use
case: Is the client developer aware of the Pagination? The resolution of these con-
cerns is context-specific; for instance, frontend representations of search results in
Web applications differ from batch master data replication in Backend Integra-
tions of enterprise information systems.
With respect to behind-the-scenes changes to mutable collections, two cases have
to be distinguished. One issue that has to be dealt with is that new items might be
added while the client walks through the pages. The second issue concerns updates
to (or removal of) items on a page that has already been seen by the client. Pagina-
tion can deal with new items but will usually miss changes to already downloaded
items that happened while a Pagination “session” was ongoing.
If the page size was set too small, sometimes the result of Pagination can be
annoying for users (especially developers using the API), as they have to click through
and wait to retrieve the next page even if there are only a few results. Also, human
users may expect client-side searches to filter an entire data set; introducing Pagina-
tion may incorrectly result in empty search results because the matching data items
are found in pages that have not yet been retrieved.
334 Chapter 7 Refine Message Design for Quality
Not all functions requiring an entire record set, such as searching, work (well)
with Pagination, or they require extra effort (such as intermediate data structures
on the API client side). Paginating after searching/filtering (and not vice versa)
reduces workload.
This pattern covers the download of large data sets, but what about upload? Such
Request Pagination can be seen as a complementary pattern. It would gradually
upload the data and fire off a processing job only once all data is there. Incremen-
tal State Build-up, one of the Conversation Patterns [Hohpe 2017], has this inverse
nature. It describes a solution similar to Pagination to deliver the data from the cli-
ent to the provider in multiple steps.
Related Patterns
Pagination can be seen as the opposite of Request Bundle: whereas Pagination is
concerned with reducing the individual message size by splitting one large message
into many smaller pages, Request Bundle combines several messages into a single
large one.
A paginated query typically defines an Atomic Parameter List for its input
parameters containing the query parameters and a Parameter Tree for its output
parameters (that is, the pages).
A request-response correlation scheme might be required so that the client can
distinguish the partial results of multiple queries in arriving response messages; the
pattern “Correlation Identifier” [Hohpe 2003] might be eligible in such cases.
A “Message Sequence” [Hohpe 2003] also can be used when a single large data
element has to be split up.
More Information
Chapter 10 of Build APIs You Won’t Hate covers Pagination types, discusses imple-
mentation approaches, and presents examples in PHP [Sturgeon 2016b]. Chapter 8
in the RESTful Web Services Cookbook deals with queries in a RESTful HTTP con-
text [Allamaraju 2010]. Web API Design: The Missing Link covers Pagination under
“More on Representation Design” [Apigee 2018].
In a broader context, the user interface (UI) and Web design communities have
captured Pagination patterns in different contexts (not API design and manage-
ment, but interaction design and information visualization). See coverage of the
topic at the Interaction Design Foundation Web site [Foundation 2021] and the UI
Patterns Web site [UI Patterns 2021].
Chapter 8 of Implementing Domain-Driven Design features stepwise retrieval
of a notification log/archive, which can be seen as Offset-Based Pagination [Vernon
2013]. RFC 5005 covers feed paging and archiving for Atom [Nottingham 2007].
Client-Driven Message Content (aka Response Shaping) 335
Pattern:
WisH List
How can an API client inform the API provider at runtime about the data it is
interested in?
How It Works
As an API client, provide a Wish List in the request that enumerates all desired
data elements of the requested resource. As an API provider, deliver only those
data elements in the response message that are enumerated in the Wish List
(“response shaping”).
Specify the Wish List as an Atomic Parameter List or flat Parameter Tree. As
a special case, a simple Atomic Parameter may be included that indicates a verbos-
ity level (or level of detail) such as minimal, medium, or full.
336 Chapter 7 Refine Message Design for Quality
Figure 7.5 sketches the request and response messages used when introducing a
Wish List:
Data element
Datasource
API
API Client
Endpoint
API
Response Implementation
List Evaluator
Figure 7.5 WISH LIST: A client enumerates the desired data elements of the resource
The List Evaluator in the figure has two implementation options. It often is trans-
lated to a filter for the data source so that only relevant data is loaded. Alternatively,
the API implementation can fetch a full result set from the data source and select the
entities that appear in the client wish when assembling the response data. Note that
the data source can be any kind of backend system, possibly remote, or database. For
instance, the wish translates into a WHERE clause of a SQL query when the data
source is a relational database. If a remote system is accessed via an API, the Wish
List might simply be passed on after having been validated (assuming that the down-
stream API also supports the pattern).
Example
In the Lakeside Mutual Customer Core application, a request for a customer returns
all of its available attributes.
{
"customerId": "gktlipwhjr",
"firstname": "Max",
"lastname": "Mustermann",
"birthday": "1989-12-31T23:00:00.000+0000",
"streetAddress": "Oberseestrasse 10",
"postalCode": "8640",
"city": "Rapperswil",
"email": "[email protected]",
"phoneNumber": "055 222 4111",
"moveHistory": [ ],
"customerInteractionLog": {
"contactHistory": [ ],
"classification": {
"priority": "gold"
}
}
}
To improve this design, a Wish List in the query string can restrict the result to the
fields included in the wish. In the example, an API client might be interested in only
the customerId, birthday, and postalCode:
{
"customerId": "gktlipwhjr",
"birthday": "1989-12-31T23:00:00.000+0000",
"postalCode": "8640"
}
This response is much smaller; only the information required by the client is
transmitted.
338 Chapter 7 Refine Message Design for Quality
Discussion
Wish List helps manage the different information needs of API clients. It is well
suited if the network has limited capacity and there is a certain amount of confi-
dence that clients usually require only a subset of the available data. The potential
negative consequences include additional security threats, additional complexity, as
well as test and maintenance efforts. Before introducing a Wish List mechanism,
these negative consequences must be considered carefully. Often, they are treated as
an afterthought, and mitigating them can lead to maintenance and evolution prob-
lems once the API is in production.
By adding or not adding attribute values in the Wish List instance, the API client
expresses its wishes to the provider; hence, the desire for data parsimony (or
Datensparsamkeit) is met. The provider does not have to supply specialized and opti-
mized versions of operations for certain clients or to guess data required for client
use cases. Clients can specify the data they require, thereby enhancing performance
by creating less database and network load.
Providers have to implement more logic in their service layers, possibly affecting
other layers down to data access as well. Providers risk exposing their data model to
clients, increasing coupling. Clients have to create the Wish List, the network has to
transport this metadata, and the provider has to process it.
A comma-separated list of attribute names can lead to problems when mapped to
programming language elements. For instance, misspelling an attribute name might
lead to an error (if the API client is lucky), or the expressed wish might be ignored
(which might lead the API client to the impression that the attribute does not exist).
Furthermore, API changes might have unexpected consequences; for instance, a
renamed attribute might no longer be found if clients do not modify their wishes
accordingly.
Solutions using the more complex variants introduced earlier (such as cas-
caded specifications, wildcards, or expansion) might be harder to understand and
build than simpler alternatives. Sometimes existing provider-internal search-and-
filter capabilities such as wildcards or regular expressions can be reused.
This pattern (or, more generally speaking, all patterns and practices sharing this
common goal and theme of client-driven message content) is also known as response
shaping.
Related Patterns
Wish Template addresses the same problem as Wish List but uses a possibly nested
structure to express the wishes rather than a flat list of element names. Both Wish
List and Wish Template usually deal with Parameter Trees in response messages
because patterns to reduce message sizes are particularly useful when dealing with
complex response data structures.
Client-Driven Message Content (aka Response Shaping) 339
Using a Wish List has a positive influence on sticking to a Rate Limit, as less data
is transferred when the pattern is used. To reduce the transferred data further, it can
be combined with Conditional Request.
The Pagination pattern also reduces response message sizes by splitting large
repetitive responses into parts. The two patterns can be combined.
More Information
Regular expression syntax or query languages such as XPath (for XML payloads)
can be seen as an advanced variant of this pattern. GraphQL [GraphQL 2021] offers
a declarative query language to describe the representation to be retrieved against an
agreed-upon schema found in the API documentation. We cover GraphQL in more
detail in the Wish Template pattern.
Web API Design: The Missing Link [Apigee 2018] recommends comma-separated
Wish Lists in its chapter “More on Representation Design.” James Higginbotham
features this pattern as “Zoom-Embed” [Higginbotham 2018].
“Practical API Design at Netflix, Part 1: Using Protobuf FieldMask” in the Net-
flix Technology Blog [Borysov 2021] mentions GraphQL field selectors and sparse
fieldsets in JSON:API [JSON API 2022]. It then features Protocol Buffer FieldMask
as a solution for gRPC APIs within the Netflix Studio Engineering. The authors sug-
gest that API providers may ship client libraries with prebuilt FieldMask for the
most frequently used combinations of fields. This makes sense if multiple consumers
are interested in the same subset of fields.
Pattern:
WisH tEmPLatE
How can an API client inform the API provider about nested data that it is inter-
ested in? How can such preferences be expressed flexibly and dynamically?3
3. Note that this problem is very similar to the problem of the pattern Wish List but adds the theme of
response data nesting.
340 Chapter 7 Refine Message Design for Quality
An API provider that has multiple clients with different information might simply
expose a complex data structure that represents the superset (or union) of what the
client community wants (for example, all attributes of master data such as prod-
uct or customer information or collections of operational data entities such as pur-
chase order items). Very likely, this structure becomes increasingly complex as the
API evolves. Such a one-size-fits-all approach also costs performance (response time,
throughput) and introduces security threats.
Alternatively, one could use a flat Wish List that simply enumerates desired attrib-
utes, but such a simple approach has limited expressiveness when dealing with nested
data structures.
Network-level and application-level gateways and proxies can be introduced to
improve performance, for instance, by caching. Such responses to performance issues
add to the complexity of the deployment model and network topology and come
with design and configuration effort.
How It Works
Add one or more additional parameters to the request message that mirror the
hierarchical structure of the parameters in the corresponding response mes-
sage. Make these parameters optional or use Boolean as their types so that
their values indicate whether or not a parameter should be included.
The structure of the wish that mirrors the response message often is a Parame-
ter Tree. API clients can populate instances of this Wish Template parameter with
empty, sample, or dummy values when sending a request message or set its Boolean
value to true to indicate their interest in it. The API provider then uses the mirrored
structure of the wish as a template for the response and substitutes the requested
values with actual response data. Figure 7.6 illustrates this design.
The Template Processor in the figure has two implementation options, depend-
ing on the chosen template format. If a mirror object is already received from the
wire and structured as a Parameter Tree, this data structure can be traversed to
prepare the data source retrieval (or to extract relevant parts from the result set).
Alternatively, the templates may come in the form of a declarative query, which must
be evaluated first and then translated to a database query or a filter to be applied to
the fetched data (these two options are similar to those in the List Evaluator compo-
nent of a Wish List processor shown in Figure 7.5). The evaluation of the template
instance can be straightforward and supported by libraries or language concepts
in the API implementation (for instance, navigating through nested JSON objects
with JSONPath, XML documents with XPath, or matching a regular expression).
Client-Driven Message Content (aka Response Shaping) 341
Wish Template
Desired element
Data element
Datasource
API
API Client
Endpoint
API
Implementation
Template
Processor
Example
The following MDSL service contract sketch introduces a <<Wish_Template>> high-
lighted with a stereotype:
«Service»
SampleAPI
«use» «use»
innerPayloadWishes innerPayload
In this example of an API, the client can send a CustomerEntity mirror (or
mock) object that may include PersonalData and/or Address attributes (this is
defined in the data type definition CustomerEntity). The provider can then check
which attributes were sent (ignoring the dummy values in the wish) and respond with
a filled-out CustomerEntity instance containing PersonalData and/or Address.
Discussion
Data parsimony (or Datensparsamkeit) is an important general design principle in
distributed systems that are performance- and security-critical. However, this princi-
ple is not always applied when iteratively and incrementally defining an API end-
point: it is typically easier to add things (here, information items or attributes) than
to remove them. That is, once something is added to an API, it is often hard to deter-
mine whether it can be safely removed in a backward-compatible way (without
breaking changes, that is) as many (maybe even unknown) clients might depend on
it. By specifying selected attribute values in the Wish Template instance and filling it
Client-Driven Message Content (aka Response Shaping) 343
with marker values or Boolean flags, the consumer expresses its wishes to the pro-
vider; thus, the desire for data parsimony and flexibility is met.
When implementing this pattern, several decisions have to be made, including
how to represent and populate the template. The sibling pattern Wish List men-
tions a comma-separated list of wishes as one approach, but the Parameter Trees
forming the Wish Template are more elaborate and therefore require encoding and
syntactic analysis. While highly sophisticated template notations might improve the
developer experience on the client side and performance significantly, they also run
the risk of turning into a larger, rather complex piece of middleware embedded into
the API implementation (which comes with development, test, and maintenance
effort as well as technical risk).
Another issue is how to handle errors for wishes that cannot be fulfilled, for
example, because the client specified an invalid parameter. One approach could be to
ignore the parameter silently, but this might hide real problems, for instance, if there
was a typo or the name of a parameter changed.
The pattern is applicable not only when designing APIs around business capabili-
ties but also when working with more IT-infrastructure-related domains such as soft-
ware-defined networks, virtualization containers, or big data analysis. Such domains
and software solutions for them typically have rich domain models and many con-
figuration options. Dealing with the resulting variability justifies a flexible approach
to API design and information retrieval.
GraphQL, with its type system, introspection, and validation capabilities, as
well as its resolver concept can be seen as an advanced realization of this pattern
[GraphQL 2021]. The Wish Templates of GraphQL are the query and mutation
schemas providing declarative descriptions of the client wants and needs. Note that
the adoption of GraphQL requires the implementation of a GraphQL server (effec-
tively realizing the Template Processor in Figure 7.6). This server is a particular type
of API endpoint located on top of the actual API endpoints (which become resolvers
in GraphQL terms). This server has to parse the declarative description of queries
and mutations and then call one or more resolvers, which in turn may call additional
ones when following the data structure hierarchy.
Related Patterns
Wish List addresses the same problem but uses a flat enumeration rather than a
mock/template object; both these patterns deal with instances of Parameter Tree
in response messages. The Wish Template becomes part of a Parameter Tree that
appears in the request message.
Wish Template shares many characteristics with its sibling pattern Wish List.
For instance, without client- and provider-side data contract validation against a
344 Chapter 7 Refine Message Design for Quality
schema (XSD, JSON Schema), Wish Template has the same drawbacks as the sim-
ple enumeration approach described in the Wish List pattern. Wish Templates can
become more complex to specify and understand than simple lists of wishes; sche-
mas and validators are usually not required for simple lists of wishes. Provider devel-
opers must be aware that complex wishes with deep nesting can strain and stress the
communication infrastructure.4 Processing can then also get more complex. Accept-
ing the additional effort, as well as the complexity added to the parameter data defi-
nitions and their processing, only makes sense if simpler structures like Wish Lists
cannot express the wish adequately.
Using a Wish Template has a positive influence on a Rate Limit, as less data is
transferred when the pattern is used and fewer requests are required.
More Information
In “You Might Not Need GraphQL,” Phil Sturgeon shows several APIs that imple-
ment response shaping and how they correspond to related GraphQL concepts [Stur-
geon 2017].
4. Olaf Hartig and Jorge Pérez analyzed the performance of the GitHub GraphQL API and found an
“exponential increase in result sizes” as they increased the query level depth. The API timed out on
queries with nesting levels higher than 5 [Hartig 2018].
Message Exchange Optimization (aka Conversation Efficiency) 345
The two patterns responding to these forces are Conditional Request and Request
Bundle.
Pattern:
ConditionaL rEquEst
In addition to the challenges introduced at the beginning of this section, the fol-
lowing forces apply:
• Data currentness versus correctness: API clients might want to cache a local
copy of the data to reduce the number of API calls. As copy holders, they must
decide when to refresh their caches to avoid stale data. The same considera-
tions apply to metadata. On the one hand, when data changes, chances are that
metadata about it has to change too. On the other hand, the data could remain
the same, and only the metadata might change. Attempts to make conversa-
tions more efficient must take these considerations into account.
One might consider scaling up or scaling out on the physical deployment level to
achieve the desired performance, but such an approach has its limits and is costly.
The API provider or an intermediary API gateway might cache previously requested
data to serve them quickly without having to recreate or fetch them from the
database or a backend service. Such dedicated caches have to be kept current and
invalidated at times, which leads to a complex set of design problems.5
In an alternative design, the client could send a “preflight” or “look before you
leap” request asking the provider if anything has changed before sending the actual
request. But this design doubles the number of requests, makes the client implemen-
tation more complex, and might reduce client performance when the network has a
high latency.
How It Works
If the condition is not met, the provider does not reply with a full response but
returns a special status code instead. Clients can then use the previously cached
value. In the simplest case, the conditions represented by Metadata Elements could
be transferred in an Atomic Parameter. Application-specific data version numbers
or timestamps can be used if already present in the request.
5. As Phil Karlton (quoted by Martin Fowler) notes, “There are only two hard things in Computer Sci-
ence: cache invalidation and naming things” [Fowler 2009]. Fowler provides tongue-in-cheek evidence
for this claim.
Message Exchange Optimization (aka Conversation Efficiency) 347
sends
«Domain Class»
Condition
API Provider
evaluates
calls if
condition
holds
«Domain Class»
Time-Based Condition Fingerprint-Based
Operation
Condition
- lastModified: Timestamp
- ngerprint: HashCode
- versionNumber: ID
It is also possible to implement the Conditional Request pattern within the com-
munication infrastructure, orthogonal and complementary to the application-specific
content. To do so, the provider may include a hash of the data served. The client can
then include this hash in subsequent requests to indicate which version of the data it
already has and for which data it wishes to receive only newer versions. A special con-
dition violated response is returned instead of the complete response if the condi-
tion is not met. This approach implements a “virtual caching” strategy, allowing clients
to recycle previously retrieved responses (assuming they have kept a copy).
Variants Request conditions can take different forms, leading to different variants
of this pattern:
Example
Many Web application frameworks, such as Spring, support Conditional Requests
natively. The Spring-based Customer Core backend application in the Lakeside Mutual
scenario includes ETags—implementing the fingerprint-based Conditional Request
variant—in all responses. For example, consider retrieving a customer:
HTTP/1.1 200
ETag: "0c2c09ecd1ed498aa7d07a516a0e56ebc"
Content-Type: application/hal+json;charset=UTF-8
Content-Length: 801
Date: Wed, 20 Jun 2018 05:36:39 GMT
{
"customerId": "gktlipwhjr",
...
Subsequent requests can then include the ETag received from the provider previ-
ously to make the request conditional:
If the entity has not changed, that is, If-None-Match occurs, the provider
answers with a 304 Not Modified response including the same ETag:
HTTP/1.1 304
ETag: "0c2c09ecd1ed498aa7d07a516a0e56ebc"
Date: Wed, 20 Jun 2018 05:47:11 GMT
If the customer has changed, the client will get the full response, including a new
ETag, as shown in Figure 7.9.
Message Exchange Optimization (aka Conversation Efficiency) 349
request()
call()
200, ETag: 1
request(If-None-Match: ETag 1)
304
Data unchanged,
ETag still unmodified
request(If-None-Match: ETag 1)
304
request(If-None-Match: ETag 1)
call()
200, ETag: 2
Discussion
Conditional Requests allow both clients and API providers to save bandwidth
without assuming that providers remember whether a given client has already seen
the latest version of the requested data. It is up to the clients to remind the server
about their latest known version of the data. They cache previous responses and are
350 Chapter 7 Refine Message Design for Quality
responsible for keeping track of their timestamp or fingerprint and resending this
information along with their next requests. This simplifies the configuration of the
data currentness interval. Timestamps, as one way to specify the data currentness
interval, are simple to implement even in distributed systems as long as only one sys-
tem writes the data. The time of this system is the master time in that case.
The complexity of the provider-side API endpoint does not increase if the pattern
is implemented with a filter, as shown in the preceding example. Further improve-
ments, such as additional caching of responses, can be realized for specific endpoints
to reduce provider workload. This increases the complexity of the endpoint, as they
have to evaluate the conditions, filters, and exceptions, including errors that might
occur because of the condition handling or filtering.
Providers also have to decide how Conditional Requests affect other quality
measures such as a Rate Limit and whether such requests require special treatment
in a Pricing Plan.
Clients can choose whether or not to make use of Conditional Requests,
depending on their performance requirements. Another selection criterion is whether
clients can afford to rely on the server to detect whether the state of the API resources
has changed. The number of messages transmitted does not change with Condi-
tional Requests, but the payload size can be reduced significantly. Rereading an old
response from the client cache is usually much faster than reloading it from the API
provider.
Related Patterns
Using a Conditional Request may have a positive influence on a Rate Limit that
includes response data volumes in the definition of the limit, as less data is trans-
ferred when this pattern is used.
The pattern can be carefully combined with either Wish List or Wish Template.
This combination can be rather useful to indicate the subset of data that is to be
returned if the condition evaluates to true and the data needs to be sent (again).
A combination of Conditional Requests with Pagination is possible, but there
are edge cases to be considered. For example, the data of a particular page might not
have changed, but more data was added, and the total number of pages has increased.
Such a change in metadata should also be included when evaluating the condition.
More Information
Chapter 10 in the RESTful Web Services Cookbook [Allamaraju 2010] is dedicated
to conditional requests. Some of the nine recipes in this chapter even deal with
requests that modify data.
Message Exchange Optimization (aka Conversation Efficiency) 351
Pattern:
rEquEst bundLE
How can the number of requests and responses be reduced to increase commu-
nication efficiency?
In addition to the general desire for efficient messaging and data parsimony (as
discussed in the introduction to this chapter), the goal of this pattern is to improve
performance:
• Latency: Reducing the number of API calls may improve client and provider
performance, for instance, when the network has high latency or overhead is
incurred by sending multiple requests and responses.
• Throughput: Exchanging the same information through fewer messages may
lead to a higher throughput. However, the client has to wait longer until it can
start working with the data.
One might consider using more or better hardware to meet the performance demands
of the API clients, but such an approach has its physical limits and is costly.
How It Works
1. One request with one response: Request Bundle with a single bundled
response.
2. One request with multiple responses: Request Bundle with multiple responses.
352 Chapter 7 Refine Message Design for Quality
Request
Bundle A Individual request
A A Individual response
API
API Client B Endpoint
API
Implementation
C
Request Splitter
Bundle Element
Dispatcher
Response
Assembler
Figure 7.10 REQUEST BUNDLE: Three independent requests, A, B, and C, are assembled in
a container message. The provider processes the requests and replies with a Single Bundled
Response
Message Exchange Optimization (aka Conversation Efficiency) 353
The API implementation has to split the request bundle and assemble the response
bundle. This can be as straightforward as iterating through an array that the provider-
side endpoint hands over, but it also may require some additional decision and dispatch
logic, for instance, using a control Metadata Element in the request to decide where
in the API implementation to route the bundle elements to. The API client has to split
a bundled response in a similar way if the provider returns a single bundled response.
Example
In the Lakeside Mutual Customer Core service, clients can request multiple custom-
ers from the customer’s Information Holder Resource by specifying an Atomic
Parameter List of customer Id Elements. A path parameter serves as a bundle con-
tainer. A comma (,) separates the bundle elements:
This will return the two requested customers as Data Elements, represented as
JSON objects in a bundle-level array (using the single bundled response option):
{
"customers": [
{
"customerId": "ce4btlyluu",
"firstname": "Robbie",
"lastname": "Davenhall",
"birthday": "1961-08-11T23:00:00.000+0000",
...
"_links": { ... }
},
{
"customerId": "rgpp0wkpec",
"firstname": "Max",
"lastname": "Mustermann",
"birthday": "1989-12-31T23:00:00.000+0000",
...
"_links": { ... }
}
],
"_links": { ... }
}
This example implements the pattern option Request Bundle with single bun-
dled response, introduced earlier.
354 Chapter 7 Refine Message Design for Quality
Discussion
By transmitting a bundle of requests at once, the number of messages can be reduced
significantly if the client-side usage scenarios include batch or bulk processing (for
instance, periodic updates to customer master data). As a consequence, the commu-
nication is sped up because less network communication is required. Depending on
the actual use case, client implementation effort might also decrease because the cli-
ent does not have to keep track of multiple ongoing requests. It can process all logi-
cally independent bundle elements found in a single response one by one.
The pattern adds to endpoint processing effort and complexity. Providers have
to split the request messages and, when realizing Request Bundle with multiple
responses, coordinate multiple individual responses. Client processing effort and
complexity can increase as well because clients must deal with the Request Bundle
and its independent elements, again requiring a splitting strategy. Finally, the mes-
sage payload design and processing get more complex, as data from multiple sources
has to be merged into one message.
Being independent of each other, individual requests in the Request Bundle
might be executed concurrently by the endpoint. Hence, the client should not make
any assumptions about the order of evaluation of the requests. API providers should
document this container property in the API Description. Guaranteeing a particu-
lar order of bundle elements causes extra work, for instance ordering a single bun-
dled response in the same way as the incoming Request Bundle.
The pattern is eligible if the underlying communication protocol cannot handle
multiple requests at once. It assumes that data access controls are sufficiently defined
and presented so that all bundle elements are allowed to be processed. If not, the
provider must compose partial responses indicating to the client which commands/
requests in the bundle failed and how to correct the corresponding input so that invo-
cation can be retried. Such element-level access control can be challenging to handle
on the client side.
Clients must wait until all messages in the bundle have been processed, increas-
ing the overall latency until a first response is received; however, compared to many
consecutive calls, the total communication time typically speeds up, as less network
communication is required. The coordination effort might make the service provider
stateful, which is considered harmful in microservices and cloud environments due
to its negative impact on scalability. That is, it becomes more difficult to scale out
horizontally when workload increases because the microservices middleware or the
cloud provider infrastructure may contain load balancers that now have to make sure
that subsequent requests reach the right instances and that failover procedures rec-
reate state in a suited fashion. It is not obvious whether the bundle or its elements
should be the units of scaling.
Summary 355
Related Patterns
The request and response messages of a Request Bundle form Parameter Forests
or Parameter Trees. Additional information about the structure and information
that identifies individual requests comes as one or more Id Elements or Metadata
Elements. Such identifiers might realize the “Correlation Identifier” pattern [Hohpe
2003] to trace responses back to requests.
A Request Bundle can be delivered as a Conditional Request. The pattern
can also be combined with a Wish List or a Wish Template. It must be carefully
analyzed if enough gains can be realized to warrant the complexity of a combination
of two or even three of those patterns. If the requested entities are of the same kind
(for instance, several people in an address book are requested), Pagination and its
variants can be applied instead of Request Bundle.
Using a Request Bundle has a positive influence on staying within a Rate Limit
that counts operation invocations because fewer messages are exchanged when the
pattern is used. This pattern goes well with explicit Error Reports because it is
often desirable to report the error status or success per bundle element and not only
for the entire Request Bundle.
Request Bundle can be seen as an extension of the general “Command” design
pattern: each individual request is a command according to terminology from
[Gamma 1995]. “Message Sequence” [Hohpe 2003] solves the opposite problem:
to reduce the message size, messages are split into smaller ones and tagged with a
sequence ID. The price for this is a higher number of messages.
More Information
Recipe 13 in Chapter 11 of the RESTful Web Services Cookbook [Allamaraju 2010]
advises against providing a generalized endpoint to tunnel multiple individual
requests.
Coroutines can improve performance when applying the Request Bundle pat-
tern in the context of batch processing (aka chunking). “Improving Batch Perfor-
mance when Migrating to Microservices with Chunking and Coroutines” discusses
this option in detail [Knoche 2019].
Summary
This chapter presented patterns concerned with API quality, specifically, finding the
sweet spot between API design granularity, runtime performance, and the ability to
support many diverse clients. It investigated whether many small or few large mes-
sages should be exchanged.
356 Chapter 7 Refine Message Design for Quality
Applying the Embedded Entity pattern makes the API exchange self-contained.
Linked Information Holder leads to smaller messages that can refer to other
API endpoints and, therefore, will lead to multiple round-trips to retrieve the same
information.
Pagination lets clients retrieve data sets piecewise, depending on their informa-
tion needs. If the exact selection of details to be fetched is not known at design time,
and clients would like the API to satisfy all of their desires, then Wish Lists and Wish
Templates offer the required flexibility.
Bulk messages in a Request Bundle require only one interaction. While perfor-
mance can be carefully optimized by sending and receiving payloads with the right
granularity, it also helps to introduce Conditional Requests and avoid resending
the same information to clients who already have it.
Note that performance is hard to predict in general and in distributed systems in
particular. Typically, it is measured under steady conditions as a system landscape
evolves; if a performance control shows a negative trend that runs the risk of violat-
ing one or more formally specified Service Level Agreements or other specified
runtime quality policies, the API design and its implementation should be revised.
This is a broad set of important issues for all distributed systems; it becomes even
more severe when a system is decomposed into small parts, such as microservices to
be scaled and evolved independently of each other. Even when services are loosely
coupled, the performance budget for meeting the response-time requirements of an
end user performing a particular business-level function can be evaluated only as
a whole and end-to-end. Commercial products and open-source software for load/
performance testing and monitoring exist. Challenges include the effort required to
set up an environment that has the potential to produce meaningful, reproducible
results as well as the ability to cope with change (of requirements, system architec-
tures, and their implementations). Simulating performance is another option. There
is a large body of academic work on predictive performance modeling of software
systems and software architectures (for example, “The Palladio-Bench for Modeling
and Simulating Software Architectures” [Heinrich 2018]).
Next up is API evolution, including approaches to versioning and life-cycle man-
agement (Chapter 8, “Evolve APIs”).
Chapter 8
Evolve APIs
This chapter covers patterns eligible when APIs change over time. Most successful
APIs do evolve; compatibility and extensibility are somewhat conflicting require-
ments that have to be balanced during the API life cycle. Clients and providers might
not agree on the most efficient mix. Keeping multiple versions supported is costly;
full backward compatibility might be desired. However, it is usually harder to achieve
in practice as it seems. Poor evolution decisions might disappoint customers (and
their API clients) and stress providers (and their developers).
We first motivate the need for evolution patterns and then present those we found
in practice: two patterns for versioning and compatibility management and four pat-
terns describing different life-cycle management guarantees.
This chapter corresponds to the Refine phase of the Align-Define-Design-Refine
(ADDR) process.
357
358 Chapter 8 Evolve APIs
and manage the impact of these changes on API clients. They support API owners,
designers, and their customers when answering the following question:
What are the governing rules balancing stability and compatibility with main-
tainability and extensibility during API evolution?
• Autonomy: Allowing the API provider and the client to follow different life
cycles; a provider can roll out new API versions without breaking existing
clients.
• Loose coupling: Minimizing the impact on the client forced by API changes.
• Extensibility: Making it possible for the provider to improve and extend the
API and change it to accommodate new requirements.
• Compatibility: Guaranteeing that API changes do not lead to semantic “mis-
understandings” between client and provider.
• Sustainability: Minimizing the long-term maintenance effort to support old
clients.
The different and independent life cycles, deployment frequencies, and schedules
of providers and clients of APIs make it necessary to plan API evolution early and
then continuously. They forbid making arbitrary changes to an already published
API. This problem becomes more severe as an increasing number of clients start to
use and depend on the API. The provider’s influence on the clients or ability to man-
age them may shrink if many clients exist (or the provider does not know its clients).
Public APIs are particularly challenging to evolve: if alternative providers exist, cli-
ents might prefer the most stable API being offered. However, even if no competing
provider is available, API clients might not be able to adapt to new API versions at
all and thus rely on the provider to evolve the API fairly. This is especially the case if
clients are known to have been implemented in a project by some contracted devel-
oper who is not available anymore. For example, a small company might have paid
an external consultant to integrate their online shop with a payment provider via a
payment API. By the time the API moves to a new version, this external consultant
might have moved on to another assignment.
Introduction to API Evolution 359
The evolution patterns in this chapter are concerned with conscious decisions
about the level of commitment and life-cycle support and with keeping or breaking
compatibility under different circumstances. They also describe how to communi-
cate breaking and nonbreaking changes.
Differing life cycles, deployment frequencies, and deployment dates of providers
and clients occur frequently in practice, especially in Public API and Community
API scenarios (two patterns featured in Chapter 4, “Pattern Language Introduc-
tion”). This makes it necessary to plan API evolution before any software releases
because it is difficult—or sometimes even impossible—to change an already pub-
lished API arbitrarily. Depending on the ratio of API providers and clients, it is
worthwhile to burden the provider (for maintaining older API versions) or the cli-
ent (for migrating to new API versions more often). Political factors—such as how
important a customer is—influence the solution space: to avoid losing dissatisfied
clients, the provider will invest more effort to support old API versions. In case of a
more powerful position of the provider, clients can be forced to migrate to newer API
versions more often by shortening support periods of APIs or features within an API.
Sometimes APIs are released without a strategy for maintaining and updating
them. Such an ad hoc approach leads to problems down the road resulting in bro-
ken clients and unavailability of those clients to their users. Even worse, problems
may go unnoticed when no measures are taken to prevent clients from misinterpret-
ing a message, which—while keeping an identical or at least similar syntax—has
changed semantics in a new API version (for instance, does a price element include
value added tax or not, and what is the rate?). Versioning an entire API with all its
endpoints, operations, and messages is a rather coarse-grained strategy and leads to
many—perhaps too many—released versions. Much effort may have to be spent on
the client side to track and adapt a new API version.
If no explicit guarantees are given, clients often implicitly expect an API to be
offered forever (which, in most cases, is not what a provider wants). When an API
eventually sunsets, but the client expected it to be available for eternity (especially in
the case of Public APIs with anonymous clients) or perhaps even had negotiated for
lifetime extensions, the provider’s reputation is damaged.
Sometimes providers want to change versions too often. This can result in prob-
lems with maintaining multiple versions in parallel or forcing upgrades upon their
clients. It is important to avoid customer churn from too many versions that do not
add enough value to invest the time and resources to upgrade. Moreover, some APIs
must assume that API client developers are not available all the time; in that case,
the API provider often has to support previous versions of its API. Such a situation
occurs, for example, if client developers were hired for a small business Web site that
must keep running, and they will never be paid to upgrade to a new API version.
The Stripe API [Stripe 2022] for accepting online payments might have such small
Introduction to API Evolution 361
business clients. Student term projects often use public APIs; breaking changes to
these APIs cause the project results to stop working, often after the projects ended.
v0.1
v1.1
v1.2 v1.3 v2.1
?
Aggressive Experimental Two in Limited
Obsolescence Preview Production Lifetime
Guarantee
Pattern:
VErsion idEntifiEr
How can an API provider indicate its current capabilities as well as the exis-
tence of possibly incompatible changes to clients in order to prevent malfunc-
tioning of clients due to undiscovered interpretation errors?
Sometimes organizations roll out APIs without planning how to manage their
life cycles. They might think that such planning can be just as effectively done after
rollout. However, lack of governance and versioning is one of the factors that have
caused some service-oriented architecture initiatives and projects to fail in the past
[Joachim 2013].
How It Works
Introduce an explicit version indicator. Include this Version Identifier in the API
Description and in the exchanged messages. To do the latter, add a Metadata
Element to the endpoint address, the protocol header, or the message payload.
The explicit Version Identifier often takes a numeric value to indicate evolu-
tion progress and maturity. It can be included in dedicated representation elements,
attribute/element name suffixes, parts of the endpoint addresses such as URLs,
domain names, XML namespaces, or the HTTP content type header. To avoid con-
sistency issues, the Version Identifier should appear in one and only one place in
all message exchanges supported by an API, unless clients or middleware strongly
desire to see it in several places.
To mint identifiers, the three-part Semantic Versioning pattern is frequently
used. By referring to such a structured Version Identifier, communication parties
can check whether they can understand and correctly interpret the message; incom-
patibilities are straightforward to spot and distinguish from feature extensions.
By indicating a new version with a different Version Identifier, the receiving
party can abort the interpretation of the message before any further problems occur
and report an incompatibility error (for example, in an Error Report). The API
Description can reference features that were introduced at a particular point in
time (such as at the release of a certain version) or that are available only in certain
364 Chapter 8 Evolve APIs
API versions but have been decommissioned in later versions, for example, when
using the Aggressive Obsolescence pattern.
Note that the schema of request and response message (for instance, defined as
custom media types in HTTP resource APIs) can also be versioned, possibly only
loosely aligned with the endpoint/operation versioning. Alexander Dean and Freder-
ick Blundun call this approach SchemaVer in [Dean 2014].
Also note that API evolution and implementation evolution are two differ-
ent things, as the implementation can evolve separately from the interface (and be
updated more frequently). This might lead to the use of multiple version identifiers,
one for the remote API and one for each implementation of it.
All implementation dependencies should be included in the versioning concept
(and/or backward compatibility of the dependencies must be ensured): if lower-layer
components such as a database that underpins stateful API calls have a schema that
cannot be evolved as fast as the API itself, this might slow down the release frequency.
It must be clear which of the two (or more) API versions in production use which
version of backend systems and other downstream dependencies. A “roll forward”
strategy, or adding a facade that decouples implementation versioning from API ver-
sioning, may be considered.
Example
In HTTP resource APIs, the version of different features can be indicated as follows.
The version of specific representation formats supported by the client appears in the
content-type negotiation headers of HTTP such as the Accept header [Fielding
2014c]:
GET /customers/1234
Accept: text/json+customer; version=1.0
...
The version of specific endpoints and operations becomes part of the resource
identifier:
GET v2/customers/1234
...
The version of the whole API can also be specified in the host domain name:
GET /customers/1234
Host: v2.api.service.com
...
Versioning and Compatibility Management 365
<soap:Envelope>
<soap:Body>
<ns:MyMessage xmlns:ns="http://www.nnn.org/ns/1.0/">
...
</ns:MyMessage>
</soap:Body>
</soap:Envelope>
{
"version": "1.0",
"products": [
{
"productId": "ABC123",
"quantity": 5;
"price": 5.00;
}
]
}
With a new version, the requirement of multicurrency was realized. This leads
to the new data structure and the new contents of the version element "version":
"2.0":
{
"version": "2.0",
"products": [
{
"productId": "ABC123",
"quantity": 5;
"price": 5.00;
"currency": "USD"
}
]
}
366 Chapter 8 Evolve APIs
Discussion
Use of the Version Identifier pattern allows the provider to clearly communicate
API, endpoint, operation, and message compatibility and extensibility. It reduces the
likelihood of problems due to undetected semantic changes between API versions
accidentally breaking compatibility. It also enables tracing which message payload
versions are actually used by clients.
APIs that work with Link Identifiers, such as hypermedia controls in HTTP
resource APIs, require special attention when versioning them. Endpoints and
APIs that are rather tightly coupled with each other, such as those forming an API
product, should be versioned together (in a coordinated fashion, that is). APIs
that are rather loosely coupled, such as those exposed by microservices owned
and maintained by different teams in an organization, are more challenging to
evolve. In the Lakeside Mutual case, if version 5 of the Customer Management
backend API returns Link Identifiers that refer to policy Information Holder
Resources residing in the Policy Management backend, which policy endpoint
version does Customer Management backend assume? It may not know the
Policy Management backend API version that the API client receiving the policy
links, which reside in the Customer Self-Service frontend, is capable of handling
(the mentioned components of the Lakeside Mutual architecture were introduced
in Figure 2.6).
When the Version Identifier changes, clients might be required to migrate to a
new API version even though the functionality that they rely on has not changed; this
increases the effort for some API clients.
Introducing Version Identifiers does not allow providers to make arbitrary
changes to the API, nor does it minimize the changes necessary to support old cli-
ents. However, it makes it possible to apply patters that have these benefits, for
example, when offering Two in Production. The pattern itself does not support the
decoupling of the provider and client life cycle, either, but it is required by other pat-
terns that do so. For example, implementing Two in Production and Aggressive
Obsolescence is simplified when versions are explicitly signaled.
Versioning and Compatibility Management 367
message element. In contrast, parts of the REST community condemn the use of
explicit Version Identifiers, and others encourage the use of HTTP accept and
content-type headers (for instance, see [Klabnik 2011]) to convey the version. How-
ever, in practice, many applications also use Version Identifiers in the exchanged
JSON/XML or the URL to indicate the version.
Related Patterns
A Version Identifier can be seen as a special type of Metadata Element. The
Version Identifier can be further structured, for example, by using the Semantic
Versioning pattern. The life-cycle pattern Two in Production requires explicit ver-
sioning; the other life-cycle patterns (Aggressive Obsolescence, Experimental
Preview, Limited Lifetime Guarantee) may also use it.
The visibility and role of an API drive related design decisions. For instance, the
different life cycles, deployment frequencies, and release dates of providers and clients
in a Public API for Frontend Integration scenario might make it necessary to plan
API evolution before making design decisions. Such scenarios usually do not allow pro-
viders to make arbitrary ad hoc changes to already published APIs due to the impact of
such changes on clients (for example, downtimes, resultant test and migration effort);
some or all of these clients might not even be known. A Community API providing
Backend Integration capabilities between a few stable communication parties that
are maintained on the same release cycle (and share a common roadmap) might be
able to employ more relaxed versioning tactics. Finally, a Solution-Internal API
for Frontend Integration connecting a mobile app frontend with a single backend
owned, developed, and operated by the same agile team might fall back to an ad hoc,
opportunistic approach to evolution that relies on frequent, automated unit and inte-
gration tests within a continuous integration and delivery practice.
More Information
Because versioning is an important aspect of API and service design, there is much
discussion about it in different development communities. The strategies differ
widely and are debated passionately. Opinions reach from no explicit versioning at
all because an API should always be backward compatible, according to “Roy Field-
ing on Versioning, Hypermedia, and REST” [Amundsen 2014], to the different ver-
sioning strategies compared by Mark Little [Little 2013]. James Higginbotham
describes the available options in “When and How Do You Version Your API?”
[Higginbotham 2017a] and in Principles of Web API Design [Higginbotham 2021].
Chapter 11 of SOA in Practice [Josuttis 2007] introduces a service life cycle in
the context of service-oriented architecture (SOA) design; Chapter 12 discusses
versioning.
Versioning and Compatibility Management 369
Chapter 13 of Build APIS You Won’t Hate [Sturgeon 2016b] discusses seven
options for versioning (with the Version Identifier in URLs being one of these
options) and their advantages and disadvantages. It also gives implementation hints.
Chapter 15 of SOA with REST [Erl 2013] deals with service versioning for REST.
Pattern:
sEmantiC VErsioning
How It Works
compatible fix
compatible
extension
1.3.0 1.3.1
incompatible
change
2.0.0
Figure 8.2 SEMANTIC VERSIONING. Version numbers indicate whether or not a change is
compatible
Note the difference between API versions (visible to clients) and API revisions
(chosen and handled internally by providers) that James Higginbotham explains
in “A Guide for When (and How) to Version Your API” [Higginbotham 2017b].
Chapter 14 in Principles of Web API Design [Higginbotham 2021] covers this topic
in depth.
Example
A startup wants to establish itself as a stock exchange data provider in the market.
Its first API version (version 1.0.0) offers a search operation, which searches for a
substring of the stock symbol and returns the list of matching stocks, including their
full names and their prices in USD. Upon customer feedback, the startup decides to
offer a historic search function. The existing search operation is extended to option-
ally accept a time range to provide access to historical price records. If no time range
is supplied, the existing search logic is executed and the last known quote is returned.
This version is fully backward compatible with the old version; old clients can call
this operation and interpret its results. Thus, this version is called version 1.1.0.
A bug is discovered in the search function of version 1.1.0: not all stocks con-
taining a supplied search string are found—only those that start with the string are
returned. The API contract is correct but not fully implemented and not sufficiently
tested. The API implementation is fixed and rolled out as version 1.1.1.
International customers are attracted to the services offered by the startup and
request the support of international stock exchanges. As such, the response is
extended to include a mandatory currency element. This change is incompatible
from a client point of view, so the new version is numbered 2.0.0.
Note that this example is technology-independent on purpose. The supplied data
can be transferred in any format, for example, as JSON or XML objects, and oper-
ations can be implemented using any integration technology (HTTP, gRPC, etc.).
This pattern deals with the conceptual problem of issuing version identifiers based
on the type of change introduced to the API interface and/or its implementation.
Discussion
Semantic Versioning offers high clarity with regard to expressing the impact on
compatibility of changes between two API versions. However, it increases the effort
to assign accurate Version Identifiers because sometimes it is hard to decide to
what category a change belongs. Such discussions about compatibility are especially
difficult, but they provide important insights into the changes being made. If, how-
ever, the pattern is not applied consistently, breaking changes might sneak into minor
updates; such violations should be watched for and discussed in daily standups, code
reviews, and so on.
Versioning and Compatibility Management 373
Related Patterns
Semantic Versioning requires a Version Identifier. The three-digit Version
Identifier may travel as a single string (with formatting constraints) or as an Atomic
Parameter List with three entries. API Description and/or Service Level Agree-
ment can carry the part of the versioning information that matters to clients.
More Information
More information on implementing Semantic Versioning can be found online at
Semantic Versioning 2.0.0 [Preston-Werner 2021].
For additional information on how to use semantic versioning in REST, the REST
CookBook Web site [Thijssen 2017] includes a chapter on versioning. The API Style-
book Web site also covers governance and versioning [Lauret 2017].
The Apache Avro specification [Apache 2021a] distinguishes the writer’s schema
from the reader’s schema and identifies the cases in which these schemas match
and do not match. The latter cases indicate incompatibility and/or interoperability
issues, requiring a new major version.
Alexander Dean and Frederick Blundun introduce a structure and semantics for
schema versioning [Dean 2014]. It utilizes the three version numbers of this pattern,
specifically defining their meanings in the context of data structures. The first num-
ber is called model and is changed if all data readers break. The second is revision,
which is incremented if some data readers break. The third is called addition and is
incremented if all changes are backward compatible.
LinkedIn defines breaking and nonbreaking changes in its “API Breaking Change
Policy” [Microsoft 2021].
v0.1
v1.2 Pattern:
? EXPErimEntaL PrEViEW
How can providers make the introduction of a new API, or new API version,
less risky for their clients and obtain early adopter feedback without having to
freeze the API design prematurely?
• Innovations and new features: Early access to emerging features raises cus-
tomer awareness of a new API (or version), and gives customers time to decide
whether to use the new API and initiate development projects. An iterative and
incremental, or even agile, integration development process is supported; agile
practices recommend releasing early and often.
• Feedback: Providers desire feedback from early clients and/or key accounts to
make sure they expose the right features with adequate qualities in their APIs.
Many customers want to influence the API design by providing comments and
suggestions about the developer experience.
• Focus efforts: Providers do not want to document, manage, and support API
prototypes with the same level of rigor as official versions. This helps focus
their efforts and saves resources.
• Early learning: Consumers want to learn about new APIs or API versions early
so that they can plan ahead and build innovative products that leverage the
new features.
• Stability: Consumers appreciate stable APIs in order to minimize change
efforts caused by frequent updates that they cannot benefit from (yet).
The provider could just release a new full-fledged API version when the develop-
ment is finished. However, this means that clients cannot start developing and testing
against the API until the release date. Developing the first client implementations
376 Chapter 8 Evolve APIs
might take several months; during this time, the API cannot be used, which results in
revenue losses (for commercial API providers).
One way to counter these problems is to release API versions frequently. While
this practice allows the client to sneak a peek at an API, the provider has to man-
age many versions. The provider will probably release many incompatible changes,
which increases the governance effort further and makes it difficult for clients to
closely track the latest API version.
How It Works
Experimental
Preview
API API
V2beta1 V2beta2
Incompatible
Development Changes
Without Guarantees
beneficial for clients who have to estimate the effort required to integrate with the
final version or who would like to jumpstart their own development while the API
development is ongoing.
The Experimental Preview, which covers the prerelease guarantees, often is
complemented by an application of Two in Production for governing the life cycle
of production APIs. The Experimental Preview can be made available to all known
or unknown clients; alternatively, a closed user group can be selected for it (to limit
support and communication effort).
Example
Let us assume that a fictitious software tools company wants to create a new product
that lets it leave its comfort zone because it goes beyond the functionality offered in
existing products. The company has been active in the development of a continuous
build and deployment solution, currently offered as a cloud software service with a
Web-based online user interface. Development teams at customers of the software tools
company use the service to build their software by fetching a revision from a repository
and deploying the built artifacts to configurable servers. Large customers have now
requested an API to better trigger and manage builds and receive notifications about
build states besides the Web interface. Because the software tools company has not yet
offered any APIs for its products and thus lacks related knowledge and experience, the
developers choose an Experimental Preview of the API and improve it continuously
by incorporating feedback from the customers who decide to adopt it early.
Discussion
Experimental Previews grant clients early access to API innovations and receive the
opportunity to influence the API design. This is faithful to agile values and principles
such as welcoming change and responding to it continuously. Providers have the flex-
ibility to change the API freely and rapidly before declaring it stable. Learning and
helping the provider to try out a new API and its features is different from writing
production applications. Providers can introduce a grace period to ease the transi-
tion from preview to the production version. Early adopters perform a sort of accept-
ance testing, as they might find inconsistencies and missing functionality in this API
version, resulting in changes without requiring the provider to follow a full-blown
governance process.
As a downside, providers may find it difficult to attract clients due to a lack of
long-term commitment to the experimental API, being perceived as immature. Cli-
ents have to keep changing their implementation until a stable version is released.
Clients might face a total loss of investment if a stable API is never released and/or
the preview disappears suddenly.
378 Chapter 8 Evolve APIs
Related Patterns
Experimental Preview is similar to traditional beta (testing) programs. This is the
weakest support commitment given by an API provider (followed by Aggressive
Obsolescence). When transitioning the API to a productive environment, another
life-cycle governance pattern must be chosen, for instance, Two In Production and/
or Limited Lifetime Guarantee. When the N in Production variant of Two In Pro-
duction is applied, an Experimental Preview can be combined with any of these
patterns.
The Experimental Preview may have a Version Identifier but does not have to.
An API Description should clearly state which version is experimentally previewed
and which one is productive. Specific API Keys can be assigned to grant certain
clients access to the preview/the beta version.
More Information
Vimal Maheedharan shares tips and tricks on beta testing in his article “Beta Testing
of Your Product: 6 Practical Steps to Follow” [Maheedharan 2018].
James Higginbotham advises keeping supported and unsupported operations
separate and getting feedback early and often. He recommends the following stabil-
ity states of API operations: experimental, prerelease, supported, deprecated, and
retired [Higginbotham 2020].
Life-Cycle Management Guarantees 379
Pattern:
aggrEssiVE obsoLEsCEnCE
How can API providers reduce the effort for maintaining an entire API or its
parts (such as endpoints, operations, or message representations) with guaran-
teed service quality levels?
How It Works
(2) Deprecate
functionality of V1
(on any date)
API Versions
V1
(1) Release API V1 (3) Remove
functionality of V1
V2
Deprecation time
Period
Figure 8.4 Stepwise approach to AGGRESSIVE OBSOLESCENCE: The API provider first releases
V1 of API functionality. While this version is available, the provider deprecates and then
removes it
The Aggressive Obsolescence strategy is eligible when the needs of the provider
outweigh those of the clients. By clearly announcing the deprecation and removal
schedule for old versions of APIs or API parts, the provider can reduce and limit
effort for supporting API parts that are not support-worthy in a broad sense, such
as economically, because a feature is too costly to maintain (for example, rarely used
features), or legally, because some functionality becomes unavailable. For instance,
the introduction of the International Bank Account Number (IBAN) to identify
bank accounts replaced old account numbers, and the introduction of the euro cur-
rency replaced many other currencies; APIs dealing with accounts and currencies
had to be changed accordingly.
The notification of a deprecation and later decommissioning date allows clients
to plan the required effort and schedules for continuing to use the old API while they
migrate to an alternative way of achieving the required functionality. Communicat-
ing which entities are deprecated and when they will be removed may require adding
special “sunset” markers, for instance, in protocol headers or Metadata Elements.
An alternative, simple solution is sending client developers an email reminding and
warning them that they are still depending on API features that will disappear soon.
Sometimes Aggressive Obsolescence might be the only option for API provid-
ers that have not yet declared any life-cycle policies. If no guarantees are given, depre-
cating features and announcing—possibly generous—transition periods might be a
proper way to be able to introduce incompatible changes.
Example
A payment provider offers an API that allows clients to instruct payments from their
accounts to other accounts. Accounts can be identified by old-fashioned, country-
specific account and bank numbers or by IBANs.2 Because IBANs are the new stand-
ard and the old account and bank numbers are rarely used, the API provider decides
not to support the old numbers anymore. This allows the provider to delete parts of
its implementation, thereby reducing maintenance effort.
In order to allow old clients to migrate to the IBAN scheme, the provider publishes
a removal announcement on its API documentation Web page, marks the account
and bank number as deprecated in the API documentation, and notifies its registered
clients. The announcement states that the old, country-specific functionality will be
removed after one year.
After one year, the payment provider deploys a new implementation of the API
that has no support for the old account and bank numbers and removes the old,
2. IBANs originally were developed in Europe but are now used in other parts of the world as well. They
have become an ISO standard [ISO 2020].
Life-Cycle Management Guarantees 383
country-specific attributes from its API documentation. Calls using the old and
removed functionality will fail from now on.3
Discussion
This pattern allows a rather fine-grained way to change APIs: in the best case, clients
do not have to change at all if functionality that becomes obsolete is not used, while
the provider code base is kept small and thus simple to maintain. The pattern can be
applied not only proactively but also reactively during API maintenance.
Providers must announce which features are deprecated and when these features
will be decommissioned. However, clients that rely on rarely used features or take
full advantage of all API features are forced to change by implementing modifica-
tions within a schedule that might have been unknown when the decision to use a
particular API was made. The decommissioning time is communicated to the cli-
ents upon deprecation and not during the API release (in contrast to the Limited
Lifetime Pattern); therefore, it might or might not fit the client’s release roadmap.
Furthermore, deprecation times and decommissioning periods might differ per API
part. Another challenge is that clients must be notified about obsolete parts, which
might be challenging in some Public API scenarios. Rightsized, pragmatic API gov-
ernance helps in this case.
Aggressive Obsolescence can be used to enforce a coherent and secure ecosys-
tem around the APIs offered: for example, replacing weak cryptographic algorithms,
out-phased standards, or inefficient libraries can help in achieving a better overall
experience for all involved parties.
The Aggressive Obsolescence pattern emphasizes the reduction of effort on the
provider side but burdens clients. Essentially, it requires the clients to evolve con-
tinuously with the API. In turn, clients stay current with the newest functions and
improvements and thus benefit from switching away from old versions; for instance,
they are forced to use new or updated (improved) security procedures. Depending on
the deprecation period, clients can plan and follow API changes but are required to
remain rather active.
Depending on the API and API endpoint types and their versioning policies,
explained in the Version Identifier and Semantic Versioning patterns, it is
not straightforward to come up with a suited deprecation and decommissioning
approach. Master data, for instance, might be harder to be removed from message
representations than operational data. It takes effort to maintain a precise list of
deprecated parts in the API Description, and it is important to plan when these
parts will eventually be removed from the API.
3. Note that in this case, legislature also had specified a transition period to the IBAN system, in effect
deprecating the old, country-specific account number scheme.
384 Chapter 8 Evolve APIs
Related Patterns
Several strategies for discontinuation of API parts can be employed, as portrayed in
the Two in Production and Limited Lifetime Guarantee patterns. The Aggres-
sive Obsolescence pattern can be used in a fine-grained way. While other strategies
are attached to entire APIs, endpoints, or operations, only certain representation ele-
ments might get deprecated and removed in Aggressive Obsolescence, thereby
allowing less obstructive changes.
Another difference to other patterns is that Aggressive Obsolescence always
uses relative timeframes for removing functionality: because functionality becomes
obsolete during the lifetime of an API, it is flagged as deprecated within its active
period, and the deprecation period runs from this time onward. In contrast, Two in
Production or Limited Lifetime Guarantee can be used with absolute timeframes
based on the initial release date.
Aggressive Obsolescence may or may not use a Version Identifier. If present,
an API Description or a Service Level Agreement should indicate its use.
More Information
Managed Evolution [Murer 2010] shares general information on service governance
and versioning, for instance, how to define quality gates and how to monitor traffic.
Chapter 7 discusses ways to measure the managed evolution.
Life-Cycle Management Guarantees 385
v1.1 Pattern:
LimitEd LifEtimE guarantEE
How can a provider let clients know for how long they can rely on the pub-
lished version of an API?
How It Works
As an API provider, guarantee to not break the published API for a fixed time-
frame. Label each API version with an expiration date.
Figure 8.5 sketches the timeline resulting from such a Limited Lifetime
Guarantee.
386 Chapter 8 Evolve APIs
e
e
t
t
Da
Da
al
e
as
ov
le
m
Re
Re
V1
API Versions
V2
V3
time
Figure 8.5 API life cycle when using LIMITED LIFETIME GUARANTEE. Removal time is stated
at publication time
The provider promises to keep the API usable for a defined, limited but consid-
erably long time and retires it after that. This practice keeps the client safe from
unwanted negative impact or outages. It also sets a fixed expiration deadline that the
client can plan for each time a version is published.
The advantage of a fixed time window serving as Limited Lifetime Guarantee
(instead of fixing the number of active versions, which is the approach taken in the
Two in Production pattern) is that no further coordination between the provider
and client organization is necessary. When using an API version for the first time, the
client already knows when it has to adapt and release a version of its application that
is compatible with the then current API version.
The Limited Lifetime Guarantee pattern stresses the stability for the client side
via a built-in expiration time; outdated versions can be decommissioned right away
when the time comes. The provider guarantees that the API will never change in an
incompatible manner in the preannounced time span and agrees to implement any
reasonable measure to keep the API up and running in a backward-compatible man-
ner during that time.
In practice, guaranteed timeframes often are multitudes of 6 months (for instance,
6, 12, 18, or 24 months), which seems to provide a good balance for provider and cli-
ent needs.
Life-Cycle Management Guarantees 387
Example
One example for a Limited Lifetime Guarantee was the introduction of the IBAN
in Europe. The limited lifetime was specified in a 2012 resolution of the European
Parliament [EU 2012] granting a period until 2014 after which the old, national
account numbers had to be replaced by the new standard; the use of IBANs became
compulsory after that. This regulatory requirement naturally had an impact on soft-
ware systems that have to identify accounts. The services offered by such systems had
to issue a Limited Lifetime Guarantee for the old API operations, which used the
old account numbers. This example shows that versioning and evolution strategies
not only are decided by the API provider alone but can also be influenced or even
mandated by external forces (such as legislation or industry consortia).
Discussion
In general, this pattern allows planning well ahead due to fixed time windows that
are known in advance. It does so by limiting the provider’s ability to respond to
urgent change requests if they impact compatibility.
Customers are forced to upgrade their API clients at a well-defined, fixed point
in time that might conflict with their own roadmap and life cycle. This can be a
problem if API clients that are still in use are no longer actively maintained. Chang-
ing existing clients might not even be possible, for instance, if a software vendor no
longer actively maintains its products.
This pattern is applicable if the provider can constrain the API evolution to
include only backward-compatible changes during the fixed lifetime guarantee. Over
time, effort to do so will increase, and the API will build up technical debt by intro-
ducing changes in a backward-compatible way that the client can still interpret. This
debt increases the effort on the provider side, for instance, for regression testing and
maintaining the API; the provider has to live with this added debt until it is permitted
to change or revoke the API.
While the Limited Lifetime Guarantee is usually part of the Service Level
Agreement between provider and client, it has large implications on the provider.
The longer the guarantee is valid, the higher the burden is on the provider devel-
opment organization. To keep the published API stable, the provider will usually
first try to make all changes in a backward-compatible manner. This might lead to
unclean interfaces with awkward names put in place in order to support both older
and newer clients. If changes cannot be (efficiently) made to the existing version, a
new API version might be developed. This new version must run in parallel with the
old version in order to fulfill the guarantee.
388 Chapter 8 Evolve APIs
Furthermore, the API freeze caused by the guarantee might inhibit progress and
integration of new technologies and features on the provider side that in turn may
also hinder clients.
In some settings, providers may want to get rid of clients who do not upgrade
when the lifetime guarantee expires. For example, due to mistakes in the API design
or progress in the area of cryptography, security risks to the whole ecosystem of the
provider and all clients might arise. Introducing the Limited Lifetime Guarantee
pattern offers an institutionalized way of enforcing timely client updates.
Related Patterns
More lenient approaches give the provider more freedom with respect to releasing
incompatible updates; they are presented in the Aggressive Obsolescence and Two
in Production patterns. The Limited Lifetime Guarantee pattern shares some
properties with Aggressive Obsolescence. In both cases, the API must not change
in an incompatible way within the announced time span. The fixed time span here in
Limited Lifetime Guarantee implies an implicit deprecation notification; the end
of the guarantee is the decommissioning time. After the guaranteed time span has
expired, the provider may make any changes, including breaking ones, or may dis-
continue the expired API version altogether.
A Limited Lifetime Guarantee usually has an explicit Version Identifier.
The API Description and, if present, a Service Level Agreement should indicate
the actual expiration date for the API version in order to inform API clients of the
upcoming need to take action and upgrade.
More Information
Managed Evolution [Murer 2010] gives rich advice on service versioning and service
management processes, for instance, including quality gates. Section 3.6 mentions
service retirement.
How can a provider gradually update an API without breaking existing clients but
also without having to maintain a large number of API versions in production?
• Allow the provider and the client to follow different life cycles: When
changing an API over time, one of the main problems is how (and for how long)
to support clients of older API versions. Keeping old API versions alive usually
requires additional resources for operations and maintenance—for instance,
bug fixes, security patches, upgrades of external dependencies, and subsequent
regression testing cause work required for each version. This inflicts cost and
binds developer resources.
It is not always possible to simply switch off an old version, because the life
cycles and evolution of API clients and their providers often differ. Even within
the same company, it is difficult or even impossible to roll out multiple sys-
tems that depend on each other at the same point in time, especially if they are
owned by different organizational units. The problem becomes worse if multi-
ple clients are owned by different organizations or if the clients are unknown to
the provider (for instance, in Public API scenarios). Thus, it is often necessary
to decouple the life cycles of the client and the provider. Enabling such autono-
mous life cycles is one of the core tenets of microservices [Pautasso 2017a].
Under independent life cycles with different API publication frequencies and
release dates of API provider implementations and their clients, it becomes neces-
sary to plan API evolution from the very beginning of API design and development
because it is impossible to make arbitrary changes to an already published API.
• Guarantee that API changes do not lead to undetected backward-
compatibility problems between clients and the provider: Introducing only
changes that are backward compatible is hard, particularly if done without
tools that automatically check for incompatibilities. There is a risk that changes
will quietly introduce problems—for instance, when changing the meaning of
existing elements in requests and responses without making the changes visible
in the message syntax. An example is the decision to include the value added tax
in a price, without changing parameter name or type. Such semantical change
cannot be detected by message receivers easily, even in API tests.
• Ensure the ability to roll back if a new API version is designed badly: When
redesigning or restructuring an API thoroughly, the new design might not work
as expected. For example, functionality still required by some clients might
unintentionally be removed. Being able to fall back and undo a change helps to
avoid breaking those clients for a while.
390 Chapter 8 Evolve APIs
How It Works
Deploy and support two versions of an API endpoint and its operations that
provide variations of the same functionality. These Two in Production do not
have to be compatible with each other. Update and decommission the versions
in a rolling, overlapping fashion.
Such a rolling, overlapping support strategy can be realized in the following way:
• Choose how to identify a version, for instance, by using the Version Identi-
fier pattern.
• Offer a fixed number (usually two, as indicated in the pattern name) of API
versions in parallel and inform your clients about this life-cycle choice.
• When releasing a new API version, retire the oldest one that still runs in produc-
tion (which is the second last one by default) and inform remaining clients (if
any) about their migration options. Continue to support the previous version.
• Redirect calls to the retired version, for instance, by leveraging protocol-level
capabilities such as those in HTTP.
API Versions V1
V2
Version V1 is removed V3
when V3 is released
V4
time
Figure 8.6 Version lifetimes when using TWO IN PRODUCTION. Clients always have a choice
between two versions
Variant Although typically two versions are offered in parallel, this pattern can
also be applied in a slightly changed variant: In N in Production more than two ver-
sions are supported.
In N in Production, the sliding window of active versions is increased to N (with N
greater than 2). This strategy gives clients more time and more options to upgrade but
places more maintenance effort and operational cost on the provider side, obviously.
Example
A business software vendor releases version 1 of a payroll API for its enterprise resource
planning (ERP) system. In the continued development of this ERP system, the payroll
API is extended with new pension plan management features. At some point, the new
features break the API because their data retention policies are incompatible with the
previously used ones; a new major version, version 2, is published. Because the vendor
supports Two in Production, it releases its software with the old API (version 1) and
the new API with pension plan management features (version 2). Customers who use
version 1 can update the ERP system and then start migrating to version 2. New
customers who need the pension plan management feature can start to use the API
version 2 right away.
With the next release of the ERP system, the software vendor again publishes a
new API (version 3) and removes support for version 1; versions 2 and 3 are now the
Two in Production. Customers that still use version 1 are cut off until they have
migrated to version 2 or 3 (that they can be redirected to). Clients using version 2 can
continue to use it until version 4 comes out. Version 5 brings end of life for version 3,
and so on.
392 Chapter 8 Evolve APIs
Discussion
Two in Production disentangles the life cycle of provider and client. API clients do
not have to release their software every time the provider does so in a breaking way.
Instead, they are granted a time window in which they can migrate, test, and release
their software updates. However, clients must move eventually, as they cannot rely on
an eternal lifetime guarantee for the API. This means that they have to plan and allo-
cate resources for upgrading their software over its lifetime as the two versions in
production come and go.
The provider can use this pattern to make brave changes in a new API version
because existing clients will stay on the old version until they migrate. This gives the
provider more freedom to refine the API incrementally.
When Two in Production is used, the effort of providers and clients are bal-
anced: customers have a defined time window to migrate their API clients to a new
API version, while API providers do not have to support an unlimited number of
versions for an undefined, possibly inappropriately long amount of time. As a result,
this pattern also clarifies the responsibilities of both parties to plan their life cycle:
the provider can introduce new and possibly incompatible versions but must support
multiple versions, whereas the client must migrate to a new version in a limited time
but can plan its release schedule rather freely and flexibly.
For clients, however, it might be difficult to know when development activity is
required: unlike in the Limited Lifetime Guarantee pattern, the removal of API
versions is dynamic and depends on other API releases. Therefore, it cannot be
planned as easily (unless the patterns are combined).
Related Patterns
The use of this pattern usually requires the Version Identifier pattern in order to
distinguish the API versions that are currently active and supported concurrently.
Fully compatible versions, for instance, as indicated by the patch version in Seman-
tic Versioning, can replace active versions without violating the Two in Produc-
tion constraints; the Two in Production are two major versions. This should be
reported in the API Description and/or the Service Level Agreement.
Aggressive Obsolescence can be applied to one of the Two in Production to
force clients to stop using the older API version and migrate to a newer one so that
the provider can introduce an even newer API version. If the client requires more
guarantees on the expiration date of the old API version, it might be better to com-
bine Two in Production with a Limited Lifetime Guarantee.
An Experimental Preview can be one of the two (or N) versions running in pro-
duction when following this pattern.
Summary 393
More Information
Managed Evolution covers life-cycle management on a general level, but also dives
into API versioning. Section 3.5.4 reports a combined usage of Semantic Version-
ing and Two in Production. Three versions are reported to have proven to be a
good compromise between provider complexity and adaptation pace [Murer 2010].
“Challenges and Benefits of the Microservice Architectural Style,” a two-part
article on the IBM Developer portal [Fachat 2019], recommends this pattern.
Summary
This chapter presented six patterns that are concerned with the evolution of APIs.
Two patterns covered versioning and compatibility management: Version Identi-
fier and Semantic Versioning. It is much easier to detect the presence and the
impact of changes if each API revision is properly identified. The Version Identi-
fier should clearly indicate whether or not the new version is compatible with previ-
ous ones. Major, minor, and patch versions should be distinguished.
The remaining four patterns focused on the API life cycle by balancing the client
desire for stability and the provider need to restrict maintenance effort. Experimen-
tal Preview helps introduce changes and get feedback about them from interested
clients without committing to their stability, as in an official release. Two In Pro-
duction eases the migration of clients by offering them two or more versions of the
API at the same time. Aggressive Obsolescence and Limited Lifetime Guaran-
tee make it explicit that no API lasts forever and clients should be aware that some-
day their dependencies will cease to function (at least in part). Obsolescence can be
declared at any time, with a grace period granted (called deprecation period); by
definition, a lifetime guarantee is established at API publication time.
A rather extreme solution for an API provider would be an experimental pre-
view in production, which could also be called “living at head” or “surfing the latest
wave.” No guarantees for compatibility are given, and clients that intend to continue
working over long periods must stay in sync with the most current API version. How-
ever, doing so requires effort and often is not a viable option.
In contrast to most other patterns in this book, only a few of the evolution pat-
terns directly affect the syntax of request and response messages: a Version Iden-
tifier may be placed in the message and use an Atomic Parameter serving as a
Metadata Element to transmit the version—whether it follows the Semantic Ver-
sioning scheme or not.
394 Chapter 8 Evolve APIs
The versioned subject can reside on different levels of abstraction: entire API,
endpoints, individual operations, and/or data types used in the request and response
messages. The same is true for the life-cycle guarantees offered in an Aggressive
Obsolescence policy. Operations applying the Request Bundle pattern are a spe-
cial case, posing the question whether all requests packaged in the request container
must have the same version. Mixing versions might be desirable but complicates
provider-side request dispatching.
Operational Data Holders that implement mission-critical, innovative fea-
tures often are often exposed to test clients and early adopters in an Experimental
Preview; they might also realize Aggressive Obsolescence and be replaced with
a newer API and API implementation frequently. Master Data Holders tend to
give longer Limited Lifetime Guarantees than other types of information holders.
Their clients benefit from a Two In Production policy particularly well. Refer-
ence Data Holders might rarely evolve; if they do, Two In Production is eligible
in this scenario, too. A long-running Processing Resource with State Transition
Operations representing business activities might not only have to migrate API and
API implementation (including database definitions) when upgrading the Version
Identifier to a new major version but also have to upgrade all process instances.
Evolution strategies should be documented in the API Description and Service
Level Agreement of the API. Rate Limits and Pricing Plans have to be changed as
the API evolves; changes in these artifacts might also trigger version upgrades.
Service Design Patterns [Daigneau 2011] includes a chapter called “Evolution.”
Two of its six patterns (Breaking Changes, Versioning) are not available online but
are presented in the book. Tolerant Reader and Consumer-Driven Contracts deal
with evolution; the remaining two patterns (Single Message Argument, Dataset
Amendment) focus on message construction and representation, which have an
impact on evolution. One particular life-cycle model is described in an IBM Redpiece
covering an API management solution [Seriy 2016].
Chapter 13 of the RESTful Web Services Cookbook [Allamaraju 2010] is devoted to
extensibility and versioning in the context of RESTful HTTP. It presents seven related
recipes—for example, how to maintain URI compatibility and how to implement cli-
ents to support extensibility. Roy Fielding expresses his views on versioning, hyperme-
dia, and REST in an InfoQ interview [Amundsen 2014]. James Higginbotham covers
the topic in “When and How Do You Version Your API?” [Higginbotham 2017a]. The
microservices movement suggests nontraditional approaches to life-cycle management
and evolution; see “Microservices in Practice: Part 2” [Pautasso 2017b] for a discussion.
Next up is Chapter 9, “Document and Communicate API Contracts,” covering
API contracts and descriptions, including both technical and business aspects.
Chapter 9
This final chapter of Part 2 collects patterns for capturing technical API specifica-
tions and sharing them with client developers and other stakeholders. We also cover
business aspects that API product owners are concerned with, including pricing and
usage constraints. Documenting software engineering artifacts might not be a popu-
lar task, but it is key to promoting API interoperability and understandability. Charg-
ing for API usage and limiting resource usage protects the current and future health
of an API. Failing to do so might not cause any major problems in the short term
(depending on the API status and criticality), but it increases business and technical
risk, possibly harming the success of the API in the long run.
Unlike previous chapters, this one does not correspond to a single phase in Align-
Define-Design-Refine (ADDR). Due to their cross-cutting nature, API specifications
and supplemental documentation artifacts can be introduced and then gradually
enhanced at any time; therefore, ADDR has a separate documentation step covering
related activities [Higginbotham 2021]. The patterns in this chapter are eligible in
this extra ADDR step.
395
396 Chapter 9 Document and Communicate API Contracts
offerings to existing and prospective clients so that these clients can decide whether a
particular offering matches their own technical and commercial expectations. A
joint understanding of the API capabilities is required in all stages of the API evolu-
tion, both during development and at runtime. Without that understanding, devel-
oper experience and software interoperability suffer. To address these concerns, the
patterns in this chapter help API product owners answer the following question:
How can the functional capabilities, quality properties, and business-related
aspects of an API be documented, communicated, and enforced?
• Interoperability: How can API client and API provider make explicit their
agreement on the functional aspects of service invocation? For example, which
data transfer representations are expected and delivered? Do any prerequisites
for successful invocation exist? And how can such functional information be
amended with other technical specification elements (such as protocol head-
ers, security policies, fault records) and business-level documentation (for
instance, operation semantics, API owner, billing information, support pro-
cedures, versioning)? Should the documentation be platform-independent or
offer protocol-level precision?
1. In Chapter 1, we defined developer experience via four pillars: function, stability, ease of use, and clarity.
Introduction to API Documentation 397
• Compliance: How can a client learn about a provider’s compliance with gov-
ernment regulations, security and privacy rules, and other legal obligations?
• Information hiding: What is the right level of detail for quality-of-service
(QoS) specifications, both avoiding underspecification (which may lead to ten-
sion between clients and providers) and overspecification (which may cause a
lot of effort in development, operations, and maintenance)?
• Economic aspects: How can an API provider select a pricing model that bal-
ances its economic interests with those of its customers and the competition?
• Performance and reliability: How can the provider maintain a satisfying per-
formance for all clients while properly economizing its resources? How can a
provider offer reliable, cost-efficient services without overly restricting the abil-
ity of clients to use its services?
• Meter granularity: How accurately and fine-grained should API consumption
be metered to satisfy client information needs without incurring unnecessary
performance penalties or reliability issues?
• Attractiveness from a consumer point of view: How can an API provider
communicate the attractiveness, availability, and performance goals of its
services to clients (assuming that more than one provider offers a certain
functionality) without making unrealistic promises that may cause client dis-
satisfaction or financial losses?
API clients might state that they want a service with a 100 percent uptime guaran-
tee, unlimited resources, and stellar performance at minimal or no cost. Of course,
this is not realistic. An API provider must strike a balance between economizing its
available resources and making a profit—or keep costs at a minimum (for example,
when providing open government offerings).
Providers can define a Pricing Plan for the API usage to bill clients or other
stakeholders. Common options are simple flat-rate subscriptions and more elaborate
consumption-based pricing.
API clients might use excessively many resources, thus negatively influencing the
service for other clients. To limit such abuse, providers can establish a Rate Limit to
restrain specific clients. The client can stick to the Rate Limit by avoiding unneces-
sary calls to the API.
Clients have to know that a provider can deliver acceptable service quality, and
providers want to deliver high-quality services while at the same time using their
available resources economically. A Service Level Agreement (SLA) expresses the
resulting compromise in targeted service-level objectives and associated penalties.
SLAs often focus on availability but can also refer to any other nonfunctional quality
property.
Figure 9.1 shows the relations between the patterns of this chapter.
complemented by enforced by
can be
refers to
part of
Service Level
Agreement
Documentation Patterns
Our final four patterns explain how to specify API contracts and how to communi-
cate and/or enforce agreed-upon API usage terms: API Description, Pricing Plan,
Rate Limit, and Service Level Agreement.
Documentation Patterns 399
Pattern:
aPi dEsCriPtion
Which knowledge should be shared between an API provider and its clients?
How should this knowledge be documented?
One could choose to provide only basic information such as network addresses
and examples of API calls and responses, and many public APIs do just this. Such an
approach leaves room for interpretation and is a source of interoperability problems.
It offloads work of the API team on the provider side because less information has
to be updated during service evolution and maintenance. This comes at the expense
of creating extra learning, experimentation, development, and testing effort on the
client side.
Documentation Patterns 401
How It Works
Create an API Description that defines request and response message struc-
tures, error reporting, and other relevant parts of the technical knowledge to
be shared between provider and client.
In addition to static and structural information, also cover dynamic or behavioral
aspects including invocation sequences, pre- and postconditions, and invariants.
Complement the syntactical interface description with quality management
policies as well as semantic specifications and organizational information.
Make the API Description both human- and machine-readable. Specify it either
in plain text or in a more formal language, depending on the supported usage sce-
nario, development culture, and maturity of the development practices.
Make sure that the semantic specification is business-aligned but also technically
accurate; it must unveil the supported business capabilities in domain terms so that it
is understandable for business analysts (aka domain subject matter experts) but also
cover data management concerns such as consistency, freshness, and idempotency.
Cover licensing and terms and conditions or factor out this information and define
a Service Level Agreement (for example, for business- and mission-critical APIs).
Consider using a recognized functional contract description language such as
OpenAPI Specification (formerly known as Swagger) for the technical contract part
of HTTP resource APIs. Note that OpenAPI Specification (OAS) Version 3.0 has an
attribute to share license information.
Variants Two variants are popular in practice: Minimal Description and Elaborate
Description. They represent opposite ends of a spectrum; hybrid forms can be found
as well.
Minimal API
Description
Example
The “Template for Elaborate API Descriptions” in Figure 9.4 covers both business
information and functional-technical API design concerns.
Figure 9.4 Template for Elaborate API Descriptions (also known as service contracts).
IDL: interface description language; FSM: finite-state machine
In practice, descriptions of APIs are often made available via developer portals,
project wikis, or service documentation Web sites. MDSL, introduced in Appendix C,
“Microservice Domain-Specific Language (MDSL),” supports the API Description
pattern natively.
Discussion
A Minimal Description is compact and easy to evolve and maintain. Elaborate
Descriptions are expressive. They promote interoperability.
404 Chapter 9 Document and Communicate API Contracts
Related Patterns
All other patterns in this book are related to this one way or another. Depending on
mission criticality and market dynamics, an API Description can be completed with
a Service Level Agreement to specify quality goals—and the consequences of not
meeting them. Version information and evolution strategies can be included (see, for
instance, Version Identifier and Two in Production patterns).
“Service Descriptor” [Daigneau 2011] and “Interface Description” [Voelter 2004]
cover the technical part of the API Description.
More Information
An online API Stylebook collects and references related documentation advice in a
dedicated “design topic” [Lauret 2017]. Recipe 14.1 in the RESTful Web Services
Cookbook [Allamaraju 2010] discusses how to document RESTful Web services.
The “Engagement Perspective” in Perspectives on Web Services [Zimmermann 2003]
collects WSDL (and SOAP) best practices; much of the given advice also applies to
other API contract syntaxes. Chapter 13 in Principles of Web API Design [Higgin-
botham 2021] covers different API description formats and other components of an
effective API documentation.
The “Microservices Canvas” template proposed by Chris Richardson creates
Elaborate Descriptions when filled out completely. The template includes implemen-
tation information, service invocation relationships, and events produced/subscribed
to [Richardson 2019].
The notion of Design-by-Contract was established by Bertrand Meyer in the con-
text of object-oriented software engineering [Meyer 1997]; his advice can also be
adopted when defining remote API contracts. The specific role of data in interface
contracts is explained by Pat Helland in “Data on the Outside versus Data on the
Inside” [Helland 2005].
The practice collection Design Practice Reference (DPR) features a Stepwise Ser-
vice Design activity and an API Description artifact [Zimmermann 2021b]. MDSL
implements the pattern [Zimmermann 2022].
406 Chapter 9 Document and Communicate API Contracts
$$$
Pattern:
PriCing PLan
How can the API provider meter API service consumption and charge for it?
When metering and billing, the following concerns are challenging to resolve in a
way that is acceptable both for API customers and for their providers:
that others exist (not even in error situations in which detailed Error Reports
are collected). Those other tenants might include competitors or business part-
ners; nondisclosure agreements might have been signed. While tenants might
be interested in performance data of other tenants, sharing such data deliber-
ately or accidentally is unethical (or even illegal).
One could just invoice the customer a one-off sign-up fee, but such an approach
might treat hobbyists and high-volume corporate users equally. This is a valid solu-
tion in some cases but might also oversimplify the picture and be too cheap for cer-
tain user segments and too expensive for others.
How It Works
Assign a Pricing Plan for the API usage to the API Description that is used
to bill API customers, advertisers, or other stakeholders accordingly.
Define and monitor metrics for measuring API usage, such as API usage
statistics per operation.
Variants Several variants of Pricing Plans exist. The most common ones are sub-
scription-based pricing and usage-based pricing. A market-based allocation is seen
less often (also known as auction-style allocation of resources). These plans can be
combined with a freemium model where a particular low or hobbyist usage level
is free. Payment comes into effect for higher usages or once an initial trial period
expires. Combinations of different plans are also possible, for example, a monthly
base flat-rate subscription fee for a base package and extra usage-based pricing for
additionally consumed services.
Subscription-based Pricing
Periodic Fee
Fee is independent of
actual usage. Period
typically is month or
year.
• Usage-based Pricing (see Figure 9.6). A usage-based pricing policy bills the cus-
tomer only for actual usage (for example, API calls or amount of data trans-
ferred) of the service resources. The pricing can be varied for different API
operations; for instance, a simple reading of a resource might cost less than
creating a resource. This usage can then be billed periodically. An alternative is
to offer prepaid packages (as is sometimes done in mobile telephony contracts)
with credits that are then spent.2
Usage-based Pricing
Measurement
Defines resource units
Specification
that are priced and
how unit usage will be
measured.
2. For example, when using CloudConvert, a document-conversion SaaS, customers can purchase pack-
ages of conversion minutes that can then be spent over time.
Documentation Patterns 409
Market-based Pricing
Resource
Client A Client B
These variants of Pricing Plans differ in the effort required to define and update
the prices; they have an impact on attracting and retaining customers. They also dif-
fer in their ambitions to make sustainable profits. Finally, they may differ in their
scope: entire API endpoint versus individual operations and API access versus back-
end services (for example, actual computing/data retrieval/communication) are two
such scoping dimensions.
Client developers and application owners are advised to read the fine print and
run some trials to familiarize themselves with the billing granularity and operational
procedures before committing to using a particular offering. Some experimentation
might be necessary to find an API consumption profile that is both technically and
financially satisfying for them.
Example
Imagine a fictitious provider offering an API to programmatically send and receive
e-mails, liberating clients from working with the SMTP and POP/IMAP protocols
directly. The provider decided to implement a usage-based Pricing Plan, with a
freemium level for low usage and different pricing levels depending on how many
e-mails per month are sent, as shown in Table 9.1.
410 Chapter 9 Document and Communicate API Contracts
Table 9.1 Usage-Based PRICING PLAN of a Fictitious API Provider with Different Billing Levels.
E-Mails per Month (up to) Pricing per Month
100 Free
10,000 $20
100,000 $150
1,000,000 $1,000
A competitor of the provider, trying to differentiate itself and keep the monitor-
ing at a minimum, might instead decide to go with a flat-rate subscription fee of $50
per month that offers unlimited e-mails to customers.
Discussion
By using a Pricing Plan, customers and their provider reach a clear agreement about
incurring costs and their mutual obligations (for example, with regard to invoicing
and payment settlement). A Pricing Plan is sometimes also called a Rate Plan.
Writing and publishing sensible Pricing Plans is challenging. It requires much
knowledge about the customers’ interests and business models on both sides. The
API product owner and developers must work together closely to pick a variant
that balances effort and benefit. API clients have to be identified by an API Key or
some other means of authentication. Usage-based pricing requires detailed moni-
toring and measurement of client actions. To avoid disputes, customers will want
detailed reporting to track and monitor their API usage. This requires more effort
on the provider’s side. Limits can be put in place that trigger a notification when
exceeded.
Another consideration is how to deal with outages of the metering functions of
the Pricing Plan implementation: if metering cannot be performed, it is impossible
to bill the customer for its consumption later. Consequently, the API has to be shut
down until the metering system is available again, or its services have to be provided
free of charge during the outage.
Subscription-based pricing is much easier to implement than usage-based pric-
ing; development should inform nontechnical stakeholders (such as product owners)
about the consequences of the more expensive implementation option. If possible,
one can start with subscription-based pricing and implement usage-based pricing at
a later stage.
Security requirements have to be satisfied by the underlying API implementation
and operational infrastructure.
Documentation Patterns 411
Related Patterns
A Pricing Plan can use Rate Limits to enforce different billing levels. If used, the
Pricing Plan should refer to the Service Level Agreement.
To identify the client making a request, an API Key (or another authentication
practice) can be used. A Wish List or a Wish Template can help to keep costs low if
the amount of data transferred is part of the Pricing Plan definition.
More Information
“API Gateway” [Richardson 2016] and the systems management patterns in Enter-
prise Integration Patterns [Hohpe 2003], “Wire Tap” and “Message Store” in par-
ticular, can be used to implement metering and serve as enforcement points. A Wire
Tap can be inserted between the source and destination of a message to copy incom-
ing messages to a secondary channel or a Message Store that is used to count the
requests per client without having to implement this at the API endpoint.
Pattern:
ratE Limit
How can the API provider prevent API clients from excessive API usage?3
When preventing excessive API usage that may harm provider operations or other
clients, solutions to the following design issues have to be found:
3. The API provider defines what exactly is deemed excessive. A paid flat-rate subscription typically
imposes different limitations than a free usage plan. See the Pricing Plan pattern for a detailed discus-
sion of the trade-offs of different subscription models.
412 Chapter 9 Document and Communicate API Contracts
their enforcement because of the extra work involved (for example, to stay
aware of its allowances). This can be a criterion for the client to move to a
competitor. Measures thus should only be taken if impact and severity of API
abuse are judged as sufficiently high to warrant the costs and business risks.
• Performance: The API provider typically wants, or might be required by
contract or regulation, to maintain a high quality of its service for all its API
clients. The exact details might be defined in the respective Service Level
Agreement.
• Reliability: If any API client abuses the service deliberately or accidentally,
actions must be taken to stop harm to other clients. Individual requests can
be rejected or access to the API revoked. If a provider is too restrictive, it runs
the risk of dissatisfying prospective consumers; if it is too relaxed, it gets over-
whelmed and the response times perceived by other consumers (for example,
paying consumers) might suffer. Those other clients might start looking for
alternatives in that case.
• Impact and severity of risks of API abuse: The possible negative conse-
quences of API clients abusing the service deliberately or accidentally have
to be analyzed and assessed. These consequences have to be weighed against
the costs of any measure taken to prevent abuse. For example, the foreseeable
usage patterns might indicate a low probability of negative consequences of
abuse and/or a low impact of such abuse (for example, economic impact or
reputation damage). If the remaining risks can be mitigated or accepted, the
API provider might decide not to take any action to prevent API clients from
excessive API usage.
• Client awareness: Responsible clients will want to manage their allowance.
They monitor their usage so they do not risk being locked out for exceeding
their limit.
To prevent clients that exhibit excessive usage from harming other API clients,
one could simply add more processing power, storage space, and network band-
width. Often this is not economically viable.
How It Works
Introduce and enforce a Rate Limit to safeguard against API clients that
overuse the API.
Documentation Patterns 413
Formulate this limit as a certain number of requests that are allowed per time
window. If the client exceeds this limit, further requests can either be declined, be
processed in a later period, or be served with best-effort guarantees, allocating a
smaller amount of resources. Figure 9.8 illustrates such interval-based Rate Limit
with periodic resets.
STO
STOP
P
Limit
API Requests
Time Periods
Figure 9.8 RATE LIMIT: Once the client exceeds the allowed number of requests per time
period, all further requests are declined
Set the scope of the Rate Limit, which can be the entire API, a single endpoint, a
group of operations, or an individual operation. Requests do not have to be treated
uniformly. Endpoints can have varying operational costs, and token usage can thus
differ.4
Define an appropriate time period, for example, daily or monthly, per API opera-
tion or group of API operations after which the Rate Limit is reset. This interval
may be rolling. Keep track of client calls in the defined time period through monitor-
ing and logging.
A Rate Limit may also restrict the amount of concurrency allowed, that is, the
number of concurrent requests a client is allowed to make. For example, under a
free billing plan, clients could be limited to just a single concurrent request. When
a client has exceeded its Rate Limit, the provider can stop serving the client alto-
gether or slow it down (or, for commercial offerings, offer to upgrade to a higher-
cost plan). This latter case is sometimes also described as throttling. Note that the
exact terminology differs by providers, and often Rate Limit and throttling are used
interchangeably.
4. For example, retrieving a simple ID costs a single token (unit) in the YouTube API, whereas a video
upload consumes approximately 1,600 units.
414 Chapter 9 Document and Communicate API Contracts
If a client hits the Rate Limit too often, the account or corresponding API Key
can be suspended and put on a “deny list.”5
Example
GitHub uses this pattern to control access to its RESTful HTTP API: once a Rate
Limit is exceeded, subsequent requests are answered with HTTP status code 429
Too Many Requests. To inform clients about the current state of each Rate Limit
and to help clients manage their allowance of tokens, custom HTTP headers are sent
with each rate-limited response.
The following code listing shows an excerpt of such a rate-limited response from
the GitHub API. The API has a limit of 60 requests per hour, of which 59 remain:
The X-RateLimit-Reset indicates the time when the limit will be reset with a
UNIX timestamp.6
Discussion
A Rate Limit gives the provider control over the API consumption of clients. By
implementing a Rate Limit, an API provider can protect its offering from malicious
clients, such as unwelcome bots, and preserve the quality of its service. The provider
can better provision resources due to capped maximal usage, thereby improving per-
formance and reliability for all clients.
Deciding on appropriate limits is not easy. If the Rate Limit is set too high, it will
not have the desired effect. Overly aggressive limits will annoy API users. Finding
the right levels requires some experimentation and tuning. For example, a provider’s
Pricing Plan might allow for 30,000 requests per month. With no additional restric-
tions, a client could consume all these requests in a short burst of time, probably
overwhelming the provider. To mitigate this particular problem, the provider could
additionally restrict clients to just one request per second. Clients need to control
5. A deny list, or blocklist, is an access control mechanism that bars certain blocked elements but lets all
others pass. This is in contrast to an allow list, or welcome list, where only elements that are on the list
can pass.
6. UNIX timestamps count the number of seconds since January 1, 1970.
Documentation Patterns 415
their usage and manage the case of hitting the Rate Limit, for example, by tracing
their API usage and/or by queuing requests. This can be achieved by caching and pri-
oritizing API calls. A Rate Limit makes the API implementation stateful, which has
to be taken into account when scaling out.
Paid offerings offer a better way to manage Rate Limits with multiple subscrip-
tion levels and, accordingly, different limits. Excessive API usage can even be seen as
something positive (because it leads to increased revenue). However, a free service
does not have to give all of its clients the same Rate Limit either. It can instead take
into account other metrics to accommodate clients of various sizes and stages. For
example, Facebook grants API calls proportional to the number of users that have
the client app installed.
In order to measure and enforce the Rate Limit metrics, the provider has to
identify the client or user. For identification purposes, the API client has obtained a
means to identify itself at the endpoint (more precisely, at the security policy enforce-
ment point7 within the API), for instance, with an API Key or an authentication
protocol. If no sign-up is required, for example, in a free service, the endpoint has to
establish another way to identify the client, such as by IP address.
Related Patterns
The details of a Rate Limit can be part of a Service Level Agreement. A Rate
Limit can be dependent on the client’s subscription level, which is described further
in the Pricing Plan pattern. In such cases, the Rate Limit is used to enforce differ-
ent billing levels of the Pricing Plan.
Wish List or a Wish Template can help to ensure that data-bound Rate Lim-
its are not violated. The current state of the Rate Limit, for example, how many
requests remain in the current billing period, can be communicated via an explicit
Context Representation in the message payload.
More Information
“Leaky Bucket Counter” [Hanmer 2007] offers a possible implementation variant
for Rate Limit. Chapter 21 in Site Reliability Engineering [Beyer 2016] covers strate-
gies for handling overload.
The systems management patterns published by [Hohpe 2003] can help to imple-
ment metering and can thus also serve as enforcement points. For example, a “Con-
trol Bus” can be used to increase or decrease certain limits dynamically at runtime
7. In the eXtensible Access Control Markup Language (XACML) [OASIS 2021], the policy enforcement
point protects a resource from unauthorized access. It consults a policy decision point in the back-
ground while doing so.
416 Chapter 9 Document and Communicate API Contracts
and “Message Store” can help implement continuous monitoring of resource usage
over time.
The Cloud Architecture Center [Google 2019] presents different strategies and
techniques for the realization of Rate Limits.
Pattern:
sErViCE LEVEL agrEEmEnt
How can an API client learn about the specific quality-of-service characteris-
tics of an API and its endpoint operations?
How can these characteristics, and the consequences of not meeting them, be
defined and communicated in a measurable way?
• Business agility and vitality: The business model of an API client might rely
on the availability of a particular API service (and on some other of the previ-
ously mentioned qualities, such as scalability or privacy). Business agility and
vitality might rely on guarantees about the former three qualities, as violations
to those might disrupt the client.
• Attractiveness from the consumer point of view: Assuming that more than
one API is available that offers a required functionality, guaranteeing service
characteristics can be an expression of confidence of the provider in its own
capabilities (including API implementation and downstream systems). For
example, when choosing between two functionally similar offerings with dif-
ferent availability guarantees, consumers are more likely to go for the offering
that has a higher availability guarantee (unless other factors such as price have
higher priority and favor the API offering the lower guarantee).
Documentation Patterns 417
• Availability: The API client is usually interested in a high uptime of the API
provider services. Uptime matters in many domains and empowers API clients
to give certain guarantees to their own consumers .
• Performance and scalability: The API client is usually interested in a low
latency, and high throughput is desired on the provider side.
• Security and privacy: If an API deals with confidential or private data, the API
client is interested in the means and measures taken by the provider to ensure
security and privacy.
• Government regulations and legal obligations: Government regulations have
to be met, for example, related to personal data protection8 or mandating that
data be stored locally.9 Such regulations might prohibit local companies from
using the offerings of a foreign provider unless the provider complies with that
regulation. For example, a Swiss startup may use the services of a US provider
that complies with the Swiss-US Privacy Shield Framework. A guarantee by the
API provider can be a way to document compliance.
• Cost-efficiency and business risks from a provider point of view: A provider
wants to economize its available resources and typically also aims at being
profitable (or keep costs at a minimum—for example, in open government
offerings). Offering an unrealistically high service level guarantee or agreeing
to pay punitive penalties would require careful consideration and must be in
line with risk management strategies on the provider side. Offering any kind
of guarantees at all, if they have no clear values, is not advisable because of the
high risks and costs for implementing them and mitigating violations of the
guarantees.
The client could simply trust the provider to make commercially and technically
reasonable efforts to provide a satisfying API usage experience, and in many public
APIs as well as solution-internal APIs, this option is chosen. However, if API usage
is business critical for the client, the resulting risk might not be tolerable. One might
rely on unstructured, freeform text that states the commercial and technical terms
and conditions of API usage only informally; many public APIs provide such docu-
ments. However, such natural language documents (just like oral ad hoc agreements)
are ambiguous and leave room for interpretations that might lead to misunderstand-
ings and, in turn, to critical project situations. They might no longer be sufficient
when competitive pressure increases. When no alternative is available or there is
8. The EU General Data Protection Regulation [EU 2016] regulates how companies must protect indi-
viduals’ data that they process.
9. For instance, laws in Brazil and Russia require providers to store data locally [The Economist 2015].
418 Chapter 9 Document and Communicate API Contracts
How It Works
In any Service Level Agreement, define at least one service-level objective (SLO)
as well as penalties, compensation credits or actions, and reporting procedures for
violations of the SLA. An SLA and its SLOs must identify the API operations they
pertain to. API client developers can then study the SLA and its SLOs carefully before
committing to use a particular API endpoint and its operations. The SLA structure
should be recognizable, ideally even standardized across offerings; the writing style
should be assertive and unambiguous. Figure 9.9 shows the structure of an SLA with
its SLOs.
Derive the SLOs for each controlled service from specific and measurable quality
attributes that are relevant to the API and ideally have been specified during analy-
sis and design [Cervantes 2016]. SLOs can also arise from regulatory guidelines; for
example, personal data protection laws such as the General Data Protection Regula-
tion [EU 2016] might mandate that data is erased once it is no longer needed. SLOs
can be broadly grouped into categories; for example, the European Commission’s
SLA guidelines [C-SIG 2014] categorize SLOs into performance, security, data man-
agement, and personal data protection categories.
Documentation Patterns 419
Example
Lakeside Mutual offers a self-service application for customers to request quotations
for different kinds of insurance. As part of its new growth strategy, the company
started offering white-label insurance products. Third parties can include Lakeside
Mutual products under their own branding on their Web sites, with Lakeside Mutual
taking a small cut from the insurance premiums. To increase confidence in this offer-
ing, the following SLA was defined:
The White-Label Insurance API service has a response time of maximally 0.5 seconds.
Note that this does not include the time it takes for the request and response
to travel across the network from the API provider to the client. Furthermore, the
provider assures:
The White-Label Insurance SLO will be met for 99 percent of the requests, measured
over a 30-day window; otherwise, the customer will receive a discount credit of 10 per-
cent on the current billing period. To receive a credit, the customer must submit a claim,
including the dates and times of the incident, to the customer support center.
Discussion
The primary target audience for this pattern is the API product owner on the pro-
vider side rather than the developers of API endpoints and operations. An SLA often
is part of the terms and conditions (of services) or a master service agreement, along
with other policies such as an acceptable use policy or a privacy policy.
Clients establish a shared understanding with the provider concerning service
levels and quality levels that can be expected. An SLA may target all provided ser-
vices or a specific set of operations exposed at a particular API endpoint. For exam-
ple, SLOs relating to a personal data protection regulation will likely be handled
in an overall SLA, but data management objectives—for example, data backup
frequency—might differ per endpoint and/or operation. Well-crafted SLAs with
measurable SLOs are an indicator of service maturity and transparency. Notably,
many public APIs and cloud offerings do not expose any, or only rather weak, SLAs.
This can be attributed to market dynamics and lack of regulation.
The provider can be held accountable for failing to provide the service. Sometimes
organizations do not want to be held accountable for their failures. Establishing
clearly defined obligations like a Service Level Agreement might therefore trigger
internal organizational resistance caused by fear.
It only makes sense to define SLAs and precise SLOs, and publish them to cli-
ents if this is required (and paid for) by clients—or if providers consider it beneficial
from a business point of view. Otherwise, SLAs might cause an unnecessary business
risk, as they are often legally binding. It might be hard to fulfill them at all times;
if not asked for, why offer strong guarantees? SLAs require substantial effort to be
designed, implemented, and monitored; mitigating SLA violations also causes work.
Maintaining operations personnel to quickly deal with SLA violations is expensive.
The business risks related to SLAs can be mitigated by limiting the liability of the API
provider, for example, to offer service credits as the only penalty for SLA violations.
Alternatives to an SLA with measurable SLOs, as described in this pattern, are to
define no SLAs or to set quality goals in loose terms (that is, in an SLA with infor-
mally specified SLOs). An SLA might contain both measurable SLOs about certain
qualities and specify others only informally. Security aspects, for example, are hard
to capture formally without becoming overly complex and either unrealistic or hard
to validate. A provider might therefore agree to make “commercially reasonable
efforts” to secure its API.
SLAs can be beneficial to the API provider even in the form of an internal SLA—
yielding a variant of the pattern in which the API provider uses the SLA to specify
and measure its own performance on relevant qualities but does not share this infor-
mation with clients external to the organization. This approach may be part of Site
Reliability Engineering [Beyer 2016].
Summary 421
Related Patterns
A Service Level Agreement accompanies the API contract or the API Description
(which would refer to the Service Level Agreement ). SLAs may govern the use of
instances of many patterns in this pattern language, such as those in the representa-
tion and quality categories of this pattern language.
The details of Rate Limits and Pricing Plans can be included in a Service Level
Agreement.
More Information
Site Reliability Engineering [Beyer 2016] devotes an entire chapter to SLOs, including
their measurements, called “Service Level Indicators” (SLIs).
Jay Judkowitz and Mark Carter cover SLA, SLO, and SLI management in a blog
post in the Google Cloud Platform Blog [Judkowitz 2018].
Summary
This chapter presented four patterns that are concerned with the documentation of
APIs both from a technical and from a business point of view: API Description,
Pricing Plan, Rate Limit, and Service Level Agreement.
While an API Description focuses on capturing the API functionality, a comple-
mentary Service Level Agreement states the qualities that clients can expect from
the API explicitly. Pricing Plan brings these two aspects together, as it defines how
much clients are supposed to pay for accessing different subsets of the API function-
ality with a certain level of quality. A Rate Limit can prevent clients from exploiting
the API provider resources beyond what they pay for.
Naturally, the four patterns have strong connections to many of those in Chapters
5 to 7. The API Description should make the API endpoint role explicit: Infor-
mation Holder Resources are data-oriented, and this data differs in terms of
its usage, lifetime, and linking; Processing Resources are activity-oriented, on
granularity levels that range from simple actions to complex business processes.
The same holds for the operation responsibilities within these types of endpoints
that differ in the way they access provider-side application state: State Creation
Operation (write access), Retrieval Operation (read access), State Transition
Operation (read and write access), and Computation Function (no access). These
endpoint roles and operation responsibilities influence the need for and the content
of a Pricing Plan and a Rate Limit, and of a Service Level Agreement as well.
For example, an Information Holder Resource may charge clients depending
on the amount of data transferred and stored, while a Processing Resource may
422 Chapter 9 Document and Communicate API Contracts
want to limit how many concurrent activity requests clients may initiate and how
computing-intense such requests may be. The conventions for naming endpoints and
their operations in the API documentation should make their roles and responsibili-
ties clear at first glance.
Both Rate Limits and Pricing Plans often make use of API Keys to identify cli-
ents. The Rate Limit is affected when patterns such as Request Bundle that change
message size and exchange frequency are applied. If a Pricing Plan is in place, cli-
ents expect certain service-level guarantees—for instance, regarding performance,
availability, and API stability.
Finally, the versioning approach and the lifetime guarantees discussed in Chapter 8,
“Evolve APIs,” are part of API Descriptions and/or Service Level Agreements. It
is likely that the combination of Pricing Plan with Experimental Preview makes
less sense than charging for the consumption of APIs applying Two in Production
and/or Limited Lifetime Guarantee.
We are done with the pattern catalog! The next chapter applies them to larger,
real-world examples.
Part 3
423
This page intentionally left blank
Chapter 10
This chapter investigates API design and evolution in real-world business domains
and application genres. We present two existing API-centric systems with their con-
texts, requirements, and design challenges as larger, domain-specific examples of
pattern use. Both system have been running in production for a long time.
We return to the questions, options, and criteria for pattern selection from Chap-
ter 3, “API Decision Narratives.” To do so, the chapter applies the patterns from
Chapters 4 to 9 in combination, focusing on
The first pattern story, “Large-Scale Business Process Integration in the Swiss
Mortgage Business,” is about an existing e-government and business process digitali-
zation solution. The second one, “APIs for Offering and Ordering Processes in the
Building Construction Domain,” presents Web APIs supporting business processes
in the construction industry (construction of physical real-world buildings, that is!).
After you have read this chapter, you should be able to combine patterns from the
previous ones and employ a business-context-specific and quality-attribute-driven
approach to API design. The two sample cases provide larger and real examples of
pattern usage and explain the rationale behind it.
425
426 Chapter 10 Real-World Pattern Stories
1. System size: From a business perspective, Terravis offers three services to insti-
tutional clients and cantonal offices: (1) Query, allowing unified access to
Swiss Land Register data (subject to access permissions and auditing), (2) Pro-
cess Automation, fully digitizing end-to-end processes between different part-
ners, and (3) Nominee, allowing banks to outsource mortgage administration.
Technically, Terravis consists of approximately one hundred (micro-) services
performing different tasks such as document generation or an implementa-
tion of a business rule. Terravis integrates hundreds of partner systems and is
expected to connect to approximately one thousand systems when all partners
will be participating.
1. In German: Grundbuchdatenbezugsschnittstelle.
Large-Scale Process Integration in the Swiss Mortgage Business 427
While the initial scope of the project was to build only the Query component
that allows important participants in land registry business processes to access rel-
evant federated master data, it was quickly decided that more value can be offered
by digitizing entire business processes. This led to the definition of Terravis-owned
APIs that allow banks, notaries, and so on, to interface with Terravis, while the Land
Register API is owned by the Swiss Federation. This diversity also becomes evident in
different naming conventions and different release cycles in the APIs. Terravis must
not store nor cache Land Register data in its Query component to honor the feder-
ated, cantonal ownership of this master data.
Technical Challenges
Many of Terravis’s technical challenges originate from its complex business environ-
ment [Berli 2014]. Different partners using different software systems connect via
APIs to Terravis. This leads to technical integration problems—intensified by the
428 Chapter 10 Real-World Pattern Stories
different life cycles of all the partner systems. Synchronized deployments are impos-
sible; implementation and update frequencies are measured in months and years and
not in weeks. Thus, appropriate API evolution was one challenge.
The technical integration also was made more complex by a rather generic Land
Register API that references many details of the common Land Register data model
and thus requires clients to have intimate knowledge of this data model. Differences
between one-to-many and one-to-one relationships became apparent in workshops.
Thus, Terravis decided to offer APIs based on a new, easier-to-use data model to gain
acceptance.
While integration was planned to be a partner-to-partner or machine-to-machine
integration only, it became clear quickly that not all partners would be able to
change their systems to implement the Terravis APIs. For others, the update fre-
quency would not be as high as that of Terravis. Thus, Terravis decided to also offer
a Web-based user interface called Portal. Terravis allows every partner to work with
business process instances in the portal or via their integrated systems in parallel.
This way, partners that implement only limited functionality of an older API can use
newer functionality via the portal if required.
Trust is an essential success factor for Terravis: by demonstrating that the pro-
ject was able to (1) deliver a platform that was difficult to build, (2) maintain a high
pace of releases, and (3) deliver its services with high reliability and security, Terravis
became a respected mediator between the banks, notaries, land registries, and other
involved parties.
To establish trust with the cantons as owners of the land registries, Terravis was
obliged not to become a loophole for a central Swiss-wide land registry. Although
the platform is supposed to provide transparent access to data regardless of the
master Land Register, this obligation implied that Terravis must neither cache nor
store Land Register data. This constraint causes issues with response times for
data queries, which potentially must contact all Swiss land registries to deliver a
result.
Many important requirements are concerned with long-term maintainability (for
instance, by accommodating different life cycles, as discussed previously) and secu-
rity. Security includes using transport-level security between Terravis and all part-
ners, full auditability of transactions and business process steps being performed,
and non-reputability of instructions via the platform. Terravis was the first platform
to offer centralized signing servers that fulfilled all requirements for legally binding
electronic signatures in Switzerland; this allows parties to sign documents and thus
conduct their processes fully digitally.
At the time of writing, the platform handles more than 500,000 end-to-end land
registry business processes annually and processes even more parcel queries.
Large-Scale Process Integration in the Swiss Mortgage Business 429
Partners Terravis
Notary
and process logic (Terravis Process Automation): as illustrated in Figure 10.1, the
Terravis Portal uses only Community APIs to connect to backend services. The
Terravis Portal serves as a substitute for a partner system, which supports all func-
tions of the platform. Terravis Portal enables human users to use the system but
cannot gain the efficiency of a direct system integration. As discussed previously,
partners that are unable to quickly integrate had to be accommodated. This design
yielded an important additional function: it serves as a reference implementation
of all Terravis APIs and therefore helps in validating the API design during devel-
opment. From the point of view of the backend services, the Portal is just another
partner system.
All APIs are documented in an API Description, which consists of a Web Ser-
vices Description Language (WSDL) with corresponding XML Schemas and—
where required—a document with samples and graphical models for the data types.
However, documentation within the WSDL and XML Schemas is preferred so that
there is only a single source for all API-related information. In addition to the API
Description, Terravis defines Service Level Agreements as part of the partner
contract that is mandatory for partners to sign to get access to the Community APIs.
Such Service Level Agreements define, for instance, availability, security, and con-
fidentiality guarantees. One part of the interface contract is that all parties have
to validate the received and sent SOAP messages against the respective XML Sche-
mas. Correct interpretation of data is crucial because legally binding activities are
Large-Scale Process Integration in the Swiss Mortgage Business 431
triggered based on it. Full XML validation ensures that no syntactic interoperability
problems arise. It also reduces the risk of semantic misinterpretations between sys-
tems. Validation can be easily enabled in commonly used frameworks such as Spring
and is one layer of quality assurance and interoperability enforcement in Terravis.
Terravis does not use the API Key pattern for transferring authentication infor-
mation in a request message. Instead, it fully relies on Two-Way-SSL to authenticate
API requests via the supplied client certificate.
As outlined earlier, allowing many partner systems to co-evolve with Terravis is a
critical success factor. Thus, many evolution patterns are used in Terravis: Terravis
makes a Two-In-Production guarantee for every API that it offers. However, the
third API version is not immediately phased out. Instead, a modified version of the
Limited Lifetime Guarantee pattern is used: from the time a third API version is
released, the oldest one is scheduled for decommission within a year. This approach
strikes a balance between Terravis’s needs to reduce maintenance effort for old API
versions while still allowing partners with rare deployments the opportunity to keep
pace with API changes.
Terravis uses a customized variant of the Semantic Versioning scheme n.m.o
for assigning version numbers to API releases. The semantic of the middle number,
that is, the minor version, is relaxed to mean that two API versions with the same
major versions but different minor versions are semantically compatible in a business
sense and messages of both API versions can be transformed into each other without
loss. This relaxed definition allows for structural refactoring—if and only if seman-
tics remain completely unchanged. Fix versions (indicated by the third number) are
also used to add new minor functionality if it does not break compatibility.
Terravis uses the Version Identifier pattern to convey version information both
in the XML namespace and as an element in the header of a message. The name-
space contains only the major and minor versions and thus guarantees compatibility
for fix versions. Initially, it was deemed appropriate to also transmit the full version
as information that must not be used in business logic but can be used for diagnostic
information. Thus, the full version was stored in the separate header element. How-
ever, inevitably, according to Hyrum’s law [Zdun 2020], partners eventually relied on
this version number as on any other part of the API and implemented business logic
based on the transmitted information.
Across all APIs and components, the Error Report pattern is used. Terravis uti-
lizes a common data structure in all APIs to signal errors in a way that it is machine
readable (error codes such as MORTGAGE_NOT_FOUND). This data structure contains
context information (error details, for example, the mortgage that was not found),
and a default English error description in case the error should be presented directly
to a user or operator, for example, “Mortgage CH12345678 not found.”
432 Chapter 10 Real-World Pattern Stories
Query Component
The first developed component, which also is a prerequisite for the Process Automa-
tion component added later, is the Query component, illustrated in Figure 10.2.
Terravis/Query
getParcelIndex
getParcelsById
Land Register
The Query API has two main operations: getParcelIndex and get-
ParcelsById, which can, for example, be called by banks and notaries. The request
messages of these two Retrieval Operations provide a Context Representation
as part of the payload, which contains a message ID. During problem analysis, this ID
serves as a “Correlation Identifier” [Hohpe 2003] between incoming requests (from
Terravis partners) and outgoing calls to the land registry. getParcelIndex is used to
search for parcel IDs by a limited number of query criteria such as community, canton-
specific legacy parcel number, or an electronic rights ID (EREID). It returns a list of
parcel IDs (EGRIDs) that can be used to fetch the master data via getParcelsById.
Both operations function as a facade because they do not contain business logic
but, following the “Message Router” pattern [Hohpe 2003], serve as a technical
routing component dispatching incoming requests to land registry systems. Because
Terravis is not allowed to cache Land Register data, it has a limited set of mappings
(for instance, which land registry serves which community or which EGRIDs or
EREIDs are known to be hosted by a certain land registry) to pinpoint a land reg-
istry system. However, if no entry is found in these mappings, a Swiss-wide search
dispatching the request to every land registry system must be performed. The main
benefit of Query is the central routing: partners are not required to legally and tech-
nically clarify and set up access to Land Register data, which is a daunting task with
more than one hundred different systems. Instead, Terravis serves as an access point
from which requests are dispatched.
Large-Scale Process Integration in the Swiss Mortgage Business 433
The getParcelsById operation also utilizes the Master Data Holder and
Wish List patterns: it allows read-only access to master data stored in the land reg-
istries. An enumeration defines three possible result data sizes that can be selected
according to the current needs of the partner and on the basis of its permissions. For
example, not all partners are allowed to access the historical data of a land registry.
Only up to ten parcels may be queried at once; therefore, no additional safeguards
such as Pagination against excessive usage are implemented. As a facade, this opera-
tion can enforce a global Rate Limit on Swiss-wide requests to manage the load on
the Terravis system. Such requests are handled in their own queue, which is capped
by the number of simultaneous active requests, while searches that could be nar-
rowed in advance to one land registry are handled without a Rate Limit.
Providing access to Land Register data is a commercial service. A Pricing Plan is in
place. To create monthly invoices according to this plan, API requests by partners are
logged in a dedicated fee table in the database. Terravis charges its own service fee as well
as the land registration fees, which are then forwarded to the corresponding land registry.
Query is a read-only service. All operations changing Land Register data are clearly
separated into the Process Automation component, which is described in the follow-
ing section. Terravis thereby follows command and query responsibility separation
(CQRS) as initially described in Object-Oriented Software Construction [Meyer 1997].
Terravis/Process Automation
Document Business
Generation Rules
Figure 10.3 Overview of Terravis Process Automation with selected partners and internal
services. Each arrowhead indicates an API provider, for example Banks are both API clients
and providers of callback operations
Business processes are started by using a State Creation Operation. The names
of these operations begin with “start”—for example, startNewMortgage for
a business process that creates a new mortgage. Figure 10.4 shows selected parts,
such as a bank as an example of a partner. Names of operations that trigger a busi-
ness activity implementing the State Transition Operation pattern in its Busi-
ness Activity Processor variant start with “request.” Such operations always have
a callback operation: if, for example, Terravis requests an action from a bank, the
bank will send the result via a callback to Terravis (or vice versa). Names of call-
back operations start with “confirm” or “reject” depending on the outcome of the
business activity. Operation names starting with “do” signal a request for an activ-
ity that is not supervised by Terravis. For example, sending documents is initiated
by such operations for which Terravis cannot verify whether or not they have been
performed. Similarly, there are “notify” operations (not shown in the figure), which
will signal partial results of the business process. Both do and notify operations will
likely also be implemented as State Transition Operations but require no response
to the original client. As such, the final implementation design is left to the API pro-
vider. Finally, the process end is signaled by an “end” operation, which is sent to all
participating partners to close their respective business cases and signal success or
failure in reaching the business process goal. Thus, Terravis realizes its business pro-
cess implementations as Processing Resources in the BPM services variant.
By definition, business process services are stateful, and the design goal was to
move all state to the processes. However, there are shared stateless services that aid
the processes. For example, certain electronic documents are generated in many
Large-Scale Process Integration in the Swiss Mortgage Business 435
Bank
Generate
Create Contract Contract Signing
CaseId
Terravis
No Mortgage
Created
processes that must be digitally signed later. Such operations are offered as Compu-
tation Functions via Solution-Internal APIs.
Process Metadata Elements, such as the current process state or pending pay-
ments, are exposed via an API that utilizes the Pagination pattern for chunking
responses to reasonable sizes. Because one requirement was to display the number
of total hits, proprietary SQL extensions of Microsoft SQL Server are used to fetch
both the requested page and the total number of results in a single query. This design
speeds up the response to these APIs significantly.
The Terravis Portal that provides Web-based access to the functionality of the
Process Automation component has additional Solution-Internal APIs. This
includes the management of pending tasks via an API that also uses Pagination.
Nominee Component
The newest component of Terravis is its Nominee service. Nominee is part of the
trustee offering to banks for handling all register-based mortgages (as opposed to
paper mortgages). This component requires a bookkeeping service, which imple-
ments the Operational Data Holder pattern, the State Creation Operation
pattern to add register mortgages to the system, the State Transition Operation
pattern to change information about a register mortgage, and other State Transi-
tion Operations for marking register mortgages for approval and so on.
Whenever queries that can result in an unlimited number of response records
are offered via an API, the Pagination pattern is applied in this component as well.
Because mortgages might be moved in large batches between different owners, a var-
iant of such a transfer operation is offered as a version implementing the Request
Bundle pattern. This pattern allows moving hundreds of thousands of mortgages
between different owners in a single API operation call.
436 Chapter 10 Real-World Pattern Stories
task-focused APIs are also easier to evolve: if a change is made, only clients using
that particular API are impacted. This eliminates the effort for unaffected clients; it
also eases change impact analysis by affected parties because the change scope is nar-
rower and more clearly defined.
The initial idea to convey the full version information, including the fix version, in
a separate field failed in practice. While it was repeatedly stressed that no logic must
depend on this field, partners started to do exactly this.
The data structures implementing the Error Report pattern were extended to
allow full support for machine-readable errors and the capability to present errors
in multiple languages—a feature that fits well with Switzerland’s four official lan-
guages. The required change from unstructured errors to structured error messages
had to be introduced incrementally in different APIs. It is now done by default for
any new API or API version. The takeaway is that structured data for signaling errors
enhances the clarity of the communication. It also helps to carefully design error
conditions and other important information for the clients.
The Pagination pattern has been used more extensively over time. Initially, some
operations were designed without thinking about minimizing payload and required
processing time and resources. Problems at runtime were analyzed, identified, and
mitigated, for instance, by using this pattern. Using the full potential of the under-
lying database server to not require a second count query (instead of an object-
relational mapper such as Java Persistence API or Hibernate) resulted in a major
performance improvement.
The project found a substantial difference between generically designed APIs and
task-specific APIs: the Land Register API is designed very generically. Thus, only two
versions were released in over 10 years; the API is syntactically very stable. For requesting
updates to Land Register data, a message with generic, command-like data structures
is created and sent. This reduces the number of exposed operations to one but moves
complexity into the message payload. Due to the generic structure, the API is difficult
to learn, understand, implement, and test. In contrast, Terravis-owned schemas are
designed very specifically in the context of supported business processes in a contract-
first design, driven by stakeholder demand. These APIs are much easier to understand
and implement. However, they expose many operations and change more frequently. In
hindsight, the task-specific, domain-driven APIs turned out to be more suitable.
Overall, Terravis has been a successful platform, in part because its API design
allows full integration among many different stakeholders. Use of the patterns
presented in this book, as well as of other patterns such as “Enterprise Integra-
tion Patterns,” helped to produce well-designed APIs. While the business setting
is uncommon and complex due to the types and numbers of involved systems and
organizations, the integration of many different systems is a common challenge.
Hence, the lessons learned on this project can benefit others.
438 Chapter 10 Real-World Pattern Stories
5. Rate of change: The system is still being maintained and developed. In the
beginning, approximately 20 versions per year were released. This number
later went down to six releases per year. The development team also changed
over time: there were up to three developers plus one tester and one IT staff
member. In total, twelve people were involved.
6. Preexistence of a stable architecture: The company had no governing IT archi-
tecture, so this was a greenfield project.
7. Governance: The project team itself was required to define all architectural
constraints and management rules, but they had direct contact with the CEO.
8. Business model: The initial focus of this project was process improvement
aimed at reducing the error rate, establishing more process awareness, remov-
ing copy-and-paste redundancies, and automating processes.
The system was instrumental in achieving a 100 percent increase in sales volume
in two years and offering lower prices by having more accurate cost estimates and
thus being able to offer the concrete columns with smaller risk margins. After that
success, the project morphed into a business process improvement initiative to fur-
ther decrease overall process cost and process cycle time.
Technical Challenges
The key requirement for SACAC is the correctness of all calculations and thus the
final offer. Having to change technical decisions to more expensive options would
lead to increased costs and fewer profits or to customers not placing an order.
The dynamic environment of the project was a challenge. Because for the first-
time core processes have been improved and digitized, many changes and stake-
holders were to be managed, and new ideas came up over time. Extracting correct
requirements and understanding the current business processes were required prior
to optimizing them and developing corresponding software support. This also
included a transition from a “buy software” to “develop custom software for a spe-
cific need” mentality as well as a shift to thinking of “an integrated application land-
scape” instead of “single software systems.”
The offer process spans multiple collaborating roles such as customer, engineer,
drawer, planner, and so on. The customer requests an offer by specifying constraints
that have a great influence on the concrete column and thus the pricing. This data
must be used in CAD and structural analysis systems for designing and evaluating
the solution. Prior to this project, the business process was human-driven and sup-
ported by standalone software. This landscape was transitioned into an integrated
440 Chapter 10 Real-World Pattern Stories
software landscape using HTTP and WebDAV APIs as well as asynchronous messag-
ing following a microservice-oriented architecture.
The main architectural choices include browser-based integration, RESTful
HTTP APIs, and decoupling by using hypermedia and JSON home documents
[Nottingham 2022]. All microservices are governed by a set of common naming con-
ventions and architectural constraints, such as when to use synchronous or asynchro-
nous messaging technologies [Hohpe 2003].
Order
Mgmt.
Difference
Offer Mgmt.
Calculation
Production
Planning
External APIs
ERP
ERP CAD (Stairs)
The CAD system, which is a standalone application, was required for designing
the concrete columns. Being a standalone system with no server components, inte-
gration was challenging: the chosen solution was to offer configuration files for this
application via a virtual WebDAV [Dusseault 2007] share. WebDAV is usually used as
a file-sharing network protocol for saving and reading files on a remote server. The
files in this WebDAV implementation can be read and written like normal files, but
they also trigger business logic. For example, an upload of a valid concrete column
CAD file to the WebDAV share triggers further processing of an order process, such
as moving it to the next action.
In addition to providing file-based interfaces, the CAD integration had to map the
data model of the application. This data model is very specific to concrete columns,
while the CAD data model is a generic one designed for any type of CAD work.
Closing this semantic gap required discussions with many stakeholders before a
correct export and import of CAD data could be achieved. Another external system
was an ERP system, which lacked easy-to-consume APIs for external integration.
Thus, it was decided to use CSV files published via WebDAV to transfer data. The
third external system was integrated later. It was a different ERP system that is used
for planning concrete stairs (in response to a product scope increase) that offered
suitable Web APIs using XML payload.
APIs offered by the system itself are only meant to be used by other microservices
and therefore are Solution-Internal APIs both for Frontend Integration and for
Backend Integration. One development team is responsible for all microservices,
which allows for easy negotiation of API changes. In general, APIs are meant to be
stable. APIs might be moved from one microservice to another; however, the techni-
cal contract part of the API Description must remain compatible.
Location transparency is achieved by serving a central home document that con-
tains endpoints for all APIs. Because this project uses REST principles for integra-
tion, endpoints of resources are published in this central document. If APIs are
rearranged or new versions in a Two in Production scenario are deployed, these are
published in the central home document, which allows other microservices to still
work without redeployment.
The use of APIs is restricted, as shown in Figure 10.6. Operations that change
data must be called only by the same microservice. Calls across microservices must
use read-only APIs exclusively. But how is data changed, then? Integration of differ-
ent microservices is achieved by transclusion. Transclusion means including HTML
fragments, served by a certain microservice, in another page, possibly served by
another microservice. These transcluded pages thus might have content originating
from the other microservice, which is permitted to change data concerning orders.
In such a system, much central information is stored, which contains shared
information about an order that is used everywhere. Instead of replicating this data
442 Chapter 10 Real-World Pattern Stories
Browser
http://microservice.A
«Transclude» «Transclude»
http://microservice.B http://microservice.C
into read models residing in the database of each microservice, a read-only view in
a shared database was created. More complex solutions would not have provided
sufficient benefit given the team structure and project size. Microservices still have a
dedicated database for data, which they exclusively own.
The API as a whole was not versioned. Sometimes different versions were required
to support old and new types of business processes. In these cases, the necessary old
APIs were made available via the Two in Production pattern, and their URLs were
distinguished by a Version Identifier.
To improve the user experience, many results were displayed in increments. Thus,
the data Retrieval Operations support the Pagination pattern. This is commonly
done when customer, offer, and appointment domain object representations are
returned. Another pattern used to reduce message payload sizes is Conditional
Request. Its application avoids returning data that has not changed since the last
request for it.
Because a business process, as well as individual interactions with the system,
might consist of multiple steps and thus multiple calls to the system, a Context
Representation is passed with all API calls and HTML page requests: this includes
common elements like security information. A common requirement also addressed
in the Context Representation is the impersonation of a user by an administrative
or support account. The business context is also included, which might be a par-
ticular process step, an order, or any other business object. These context elements
are identified by their respective universally unique identifiers (UUIDs), which is in
line with the Id Element pattern, and passed on in the context. The request context
might include a “from” and a “to” jump point allowing users to easily navigate the
system. Nondefault URLs for the user to follow or to return to can be specified. This
is implemented by using Link Elements. Due to using REST and relying on hyper-
media for business process navigation as well as selecting correct API versions, Link
Elements are an important type of information passed in messages. As explained
previously, these are amended by a central JSON home document that, in our pat-
tern terms, serves as a Link Lookup Resource bringing location transparency for
API endpoints.
Requests might fail for various reasons, such as technical outages, insufficient per-
missions, or simple errors in the business logic. At first, only simple HTTP error codes
were returned. Over time, important user-facing error messages were improved by
returning an Error Report providing more information about the problem.
The system has been implemented in Ruby using Ruby on Rails. This frame-
work allows the easy implementation of some patterns. For example, Conditional
Requests are supported by the framework itself. Ruby on Rails also supports HTTP,
JSON, and REST-styled APIs well. For integrating external systems via WebDAV, a
custom library, RailsDAV, has been developed and open-sourced.
For better and easier management of the request context and transcluded content,
all microservices are accessible under one TCP/IP domain that is served by a reverse
proxy. The reverse proxy uses the URL to route requests to the correct microservices.
444 Chapter 10 Real-World Pattern Stories
This way, all assets and scripts are served from the same domain, and problems with
security measures on the browser side (for example, related to same-origin policies)
can be avoided.
Summary
This chapter presented two large examples of real-world API designs that (know-
ingly or unknowingly) applied patterns from this book. Both systems run in produc-
tion and evolved over time.
The first pattern story featured a large-scale business process integration hub and
portal for the Swiss mortgage business. We saw that many quality patterns, includ-
ing Wish List and Context Representation, were applied. The evolution patterns
Version Identifier and Two in Production also played an important role in this
scenario that involves many parties, businesses, and government organizations.
Using its Community APIs must be paid for under a Pricing Plan.
The second pattern story involved building architects in addition to software
architects and API designers. It described a Web-based offer and order management
system to custom design concrete columns for building construction sites. API pat-
terns from this book, including many of those found in the first story (for example,
Error Report) as well as endpoint role patterns such as Link Lookup Resource,
helped craft a flexible and resource-efficient software design.
Note that even if patterns are chosen and applied well, the API implementations
can still harm qualities such as extensibility, performance, consistency, and avail-
ability. Such quality-related forces and patterns addressing them have numerous
many-to-many relationships among each other and with other critical success fac-
tors. Patterns always have to be adopted and adapted to the project context; good
software engineering practices for development and testing have to be applied along
the way.
We are almost done now. A summary and outlook follow to conclude the book.
This page intentionally left blank
Chapter 11
Conclusion
Let us recapitulate the book content and reflect on the patterns for API design and
evolution as we presented them across its three parts. This chapter also points to
related research and contains our—somewhat speculative and risky—take on the
future of APIs and related architectural knowledge.
Distributed systems are the norm today. In such systems, a number of services
work together and communicate through remote APIs. When being assembled into
distributed applications, APIs and their implementations must satisfy rather diverse
integration requirements—different APIs may use different communication proto-
cols and message exchange formats, their implementation components may reside
in different security zones and/or run in different locations, and so on. Different
options are available to fine-tune the message and endpoint design according to
desired qualities and existing constraints. For instance, APIs often must be respon-
sive, scalable and reliable but also readily developer-friendly and evolvable. Many of
them automate business processes and activities involving customers, products, and
business partners; such business activities and their supporting software frequently
change in response to changes in their functional requirements and quality goals.
The purpose of the pattern language presented in this book is to help integration
architects, API developers, and other roles involved with API design and evolution
make more informed, adequate, and sound decisions when crafting APIs for a par-
ticular client community with its goals and domain contexts. Our patterns provide
proven design options for these decisions.
447
448 Chapter 11 Conclusion
Short Retrospective
We presented 44 patterns for API design and evolution, including rather common
ones such as Pagination (Chapter 7) and API Description (Chapter 9) but also less
obvious ones such as Context Representation (Chapter 6) and Two in Production
(Chapter 8). Chapter 4 provided a language overview and patterns to scope APIs and
structure messages, including Frontend Integration and Parameter Tree.
We assume that the APIs that apply these patterns exchange plain text messages
rather than remote objects. They may do so over synchronous communication chan-
nels or asynchronous, queue-based ones. Selected patterns are implemented in the
Lakeside Mutual sample application introduced in Chapter 2 and in the two real-
world cases featured in Chapter 10. While many motivating examples and known
uses of the patterns came from microservice-oriented systems, all software systems
that contain remote APIs may benefit from applying them.
Did we miss some patterns? Certainly. For instance, reactive, long-running, event-
driven API designs were only touched upon—these topics could fill an entire book.
It would also be interesting to mine patterns on advanced composite structures that
carry certain domain-specific semantics such as resource reservations, overview-
details presentations, or case management activities. One could think of turning
Martin Fowler’s Analysis Patterns [Fowler 1996] into pre-canned API designs. Books
on data modeling [Hay 1996] could provide input to such effort, and common data
definition initiatives such as microformats [Microformats 2022] and Schema.org1
would have their role to play too. Business responsibility-driven design could take a
prominent place in such “domain API” undertaking.
On the API realization level, we could distinguish aggregated, mediating “guard
resources” calling other APIs from self-contained “ground resources” that do not
depend on other APIs provided elsewhere. We could also continue to work on pat-
terns about API orchestration flows or conversations [Pautasso 2016]. Another
time—maybe. While we hinted at API implementation options, we did not cover
topics such as system transactions versus business-level compensation (ACID guar-
antees versus various forms of BASE properties) much; “Sagas” [Richardson 2018]
or “Try-Confirm/Cancel” steps [Pardon 2011] could possibly support business-level
compensation.
We only touched upon protocol specifics in examples and discussion sections; the
recipes in the RESTful Web Services Cookbook [Allamaraju 2010] and many other
books provide detailed advice regarding RESTful HTTP. The preface provided infor-
mation about related pattern languages and other good reads.
1. https://schema.org.
API Research: Refactoring to Patterns, MDSL, and More 449
We also did not put much emphasis on operating API implementations; just like
any application deployment, API implementations have to be managed at runtime.
There are many deployment and hosting options for API implementations and
service-oriented systems, including serverless functions and other cloud computing
offerings. API endpoints and, possibly, API gateways, have to be configured, secured,
accounted for, and monitored (for instance, with regard to faults and performance).
These activities fall under API management, a term that summarizes a suite of prac-
tices and tools complementary to API design and evolution.2
2. It seems that we just had the second round of buzzword bingo in this book. Do you remember the first
one?
450 Chapter 11 Conclusion
3. Maybe some semi-intelligent, format-autonomous tools can automate their application in the future?
Final Remarks 451
as other integration technologies and protocols? Is there a chance for a unified lan-
guage? Time will tell, and we look forward to finding known uses of our patterns in
these languages and API designs using them.
Additional Resources
The Web site companion to this book provides pattern summaries and additional
background information:
https://api-patterns.org
The Interface Refactoring Catalog is available here:
https://interface-refactoring.github.io
The “Stepwise Service Design” activity proposed in the software and service Design
Practice Reference (DPR) leverages many of the patterns from this book [Zimmer-
mann 2021b]. DPR also comes as an open-source repository of methods and practices
that are applicable to service analysis and design:
https://socadk.github.io/design-practice-repository
Final Remarks
While IT buzzwords and technology concepts come and go, integration styles and
design patterns stay. Patterns are not final solutions but can help you do better and
avoid common mistakes—so that you have an opportunity to make new ones, which
then become lessons learned and, eventually, lead to new patterns or antipatterns.
Please view our patterns as a starting point for your design endeavors, not as their
destination!
We are confident that the architectural knowledge captured in this book and its
patterns has the potential to guide architectural decisions on your real-world API
design and development projects. If this actually happens, we will be happy to get
your feedback on how the patterns helped you craft awesome APIs.
Thanks for buying, reading, and making it to the end of our book!
This appendix provides guidance on when to apply which pattern in the form of a
cheat sheet. It also connects our pattern language with responsibility-driven design
(RDD), domain-driven design (DDD), and the Align-Define-Design-Refine (ADDR)
process.
453
454 Appendix A Endpoint Identification and Pattern Selection Guides
Next up, in Table A.2, responsibility patterns can jumpstart API endpoint design.
Table A.2 How to Identify and Classify API Endpoints by Role (from Chapter 5)
Issue Pattern(s)
Identify API endpoint candidates Apply DDD and/or stepwise API design practice such
as ADDR or one of those compiled in Design Practice
Reference [Zimmermann 2021b]
Model a business capability that is action- Define a Processing Resource and realize the
oriented (representing business activities or required activities as well as coordination and state
commands) management in its operations (see Table A.3)
Model a business capability that is data- Define an Information Holder Resource, being
oriented aware of the coupling introduced and provide suited
create, read, update, delete, and search operations for
it (Table A.3)
Let applications exchange transient data Define a Data Transfer Resource and add API
without coupling them directly clients to the applications
Decouple provider locations from clients Provide a Link Lookup Resource as an directory
serving dynamic endpoint references
Expose short-lived, transactional data Mark an Information Holder Resource as
Operational Data Holder
Expose long-lived, mutable data Mark an Information Holder Resource as Master
Data Holder
Expose long-lived data not mutable for Mark an Information Holder Resource as
clients Reference Data Holder
During endpoint identification, one might decide to define one API or one API
endpoint for each “Bounded Context” from DDD if logic and data are highly cohe-
sive [Singjai 2021a]. If fine-grained decomposition is desired and possible, “Aggre-
gate” may initiate API and API endpoint identification [Singjai 2021b; Singjai 2021c].
Cheat Sheet for Pattern Selection 455
The operations exposed by API endpoints differ in the way they touch (or do not
touch) provider-side state: read, write, read-write, or neither read nor write (Table A.3).
Table A.5 shows how, in message payload design, both basic and structured mes-
sage elements may receive certain stereotypical roles.
456 Appendix A Endpoint Identification and Pattern Selection Guides
Table A.6 When to Apply Which Quality Improvement (from Chapters 6, 7, and 9)
Issue Pattern(s)
API clients report interoperability Switch from minimal to elaborate API Description
and usability problems Add Metadata Elements to Parameter Trees
Introduce a Context Representation in the payload
encapsulating control metadata such as quality-of-service
properties
API usage mistakes and other faults Add an Error Report to response representations to
are difficult to analyze and fix describe failures in detail
API clients report performance Switch from Embedded Entities to Linked Information
problems Holders to adjust message size and service granularity
(the two patterns can be combined flexibly)
Reduce the amount of transferred data with a Wish List or a
Wish Template
Consider other quality patterns improving data transfer
parsimony (for instance, Conditional Request or Request
Bundle)
Introduce Pagination
Access control is needed Introduce API Keys or more advanced security solutions
Cheat Sheet for Pattern Selection 457
RDD Concepts
To order and structure the endpoint and operation design space (or, in ADDR, the
Define phase), we adopt some of the terminology and the role stereotypes from RDD
[Wirfs-Brock 2002]. RDD was originally created for the context of object-oriented
analysis and design (OOAD), which becomes apparent in its core definitions:
In our experience, RDD works equally well on the code level and on the architecture
level. As API design has both architectural and developmental ramifications, the role
stereotypes in RDD are a natural choice to express API behavior. For instance, all API
endpoints can be seen to have (remote) interfacers that provide and protect access to ser-
vice providers, controllers/coordinators, and information holder roles. The read-write
operations exposed by API endpoints correspond to responsibilities. The API Descrip-
tion specifies the RDD contract, and collaborations arise from calls to API operations.
The patterns in Chapter 5 pick up these terms and concepts for the context of API
design.
• A DDD “Aggregate” can also be exposed via an API (possibly having several
endpoints, starting with the root “Entity”). Depending on the nature of an
Aggregate, a Processing Resource is often preferred over an Information
Holder Resource; see the discussions in these two patterns for rationale.
• DDD “Repositories” deal with entity life-cycle management, which involves read
and write access to API provider-side application state (as defined by our opera-
tion responsibility patterns). For instance, repositories usually provide lookup
capabilities, which may turn into API-level Retrieval Operations. Special-
purpose repositories may yield Link Lookup Resources. DDD “Factories” also
deal with life-cycle management and may donate additional API operations
(unless their functionality should remain an API-implementation detail).
• DDD “Value Objects” can be exposed as data transfer representations (DTRs)
in the Published Language established by the data part of the API Descrip-
tion. Data Element from Chapter 6 is a related pattern.
In DDD, the Aggregate and Entity patterns often expose process-like properties
(as they represent groups of domain concepts that have an identity and a life cycle at
runtime). Hence, these patterns can help identify State Creation Operation and
State Transition Operation candidates during endpoint identification. However,
it is important not to expose the entire domain model as Published Language on the
API level because this creates an undesired tight coupling between the API clients
and the provider-side API implementation.
DDD does not distinguish between master data and operational data in its tactic
patterns; both operational data and master data may be part of the Published Lan-
guage and appear in dedicated Bounded Contexts and Aggregates as Entities (see
[Vernon 2013]). In DDD, domain event sourcing [Fowler 2006] is the recommended
practice to integrate Aggregates (both within the same and in different Bounded
Contexts) because it decouples them and allows replaying events up to the current
state in case of failures that lead to consistency issues. APIs may support this.
In Principles of Web API Design, James Higginbotham reminds us that
“resources are not data models” and “resources are not objects or domain models”
[Higginbotham 2021], with resources corresponding to endpoints in our technology-
neutral terminology. And “REST was never about CRUD” either. That said, data and
domain models may still serve as API design input when taken with a grain of salt.
Align
1. Identify Digital Foundation patterns (Chapter 4) User story about “contact
Capabilities information updates” in Chapter 2
2. Capture Activity n/a The agile practice of story splitting
Steps could be applied; same for event
storming (examples available
online)*
Define
3. Identify API Foundation patterns (Chapter 4) Lakeside Mutual domain model
Boundaries and context map in Chapter 2
Responsibility patterns (Chapter 5) For example, Processing
Resource, Information Holder
Resource usage in Lakeside
Mutual
4. Model API Profiles Foundation patterns (Chapter 4) See interludes in Chapter 3
Responsibility patterns (Chapter 5) See interludes in Chapter 3
Initial Service Level Agreement See interludes in Chapter 3
(Chapter 9)
Design
5. High-Level Design Basic structure patterns (Chapter 4) See interludes in Chapter 3
Element stereotype patterns (Chapter 6) See interludes in Chapter 3
Embedded Entity and Linked The HTTP resource APIs for
Information Holder patterns Lakeside Mutual, implemented in
(Chapter 7) Java, provide examples of pattern
use (see Appendix B)
Technology realization of patterns See Appendix B
(for instance, as HTTP resources)
Refine
6. Refine the Design Quality patterns (Chapters 6 and 7) Wish List in operations of
Customer Information Holder in
Lakeside Mutual
7. Document the API API Description, Rate Limit See OpenAPI snippet in Appendix B
(Chapter 9) for a minimal technical contract
Evolution patterns such as Version See sample decisions in Chapter 3
Identifier (Chapter 8)
*
https://ozimmer.ch/categories/#Practices.
“Driven” API Design 461
More details on the Identify API Boundaries step. Our messages are very much
in line with James Higginbotham’s advice; for instance, our patterns help avoid the
antipatterns he discusses [Higginbotham 2021, p. 70 ff.]. By considering our end-
point role patterns from Chapter 5 when deciding between activity- or data-oriented
semantics of endpoints and being aware of the differences in the responsibilities of
their operations, antipatterns like the “Mega All-In-One API,” “Overloaded API,”
and “Helper API” can be avoided.
More details on the Model API Profiles step. This is an ADDR step in which
many of our patterns are eligible. For instance, the Link Element pattern and
related Metadata Elements from Chapter 6 may be used to describe the “resource
taxonomies” (independent/dependent/associative resources) [Higginbotham 2021,
p. 87], and the “operation safety classification” (safe/unsafe/idempotent operations)
[p. 91] can be expressed with the operation responsibilities from Chapter 5.
More details on the High-Level Design step. This ADDR step is complemen-
tary to our Chapters 4, 5, and 7; the patterns from these chapters fit here. A Rate
Limit (Chapter 9) can be part of the “API Management Layer.” Deciding whether
to include related or nested resources, discussed in the context of “hypermedia seri-
alization” [Higginbotham 2021, p. 127], is covered by our Embedded Entity and
Linked Information Holder patterns. Our Wish Template pattern provides com-
plementary advice on “query-based APIs.”
More details on the Refine the Design step. Note that optimizing for perfor-
mance on a platform-neutral level (as our Chapters 6 and 7 patterns do) is not cov-
ered as such in ADDR. That said, our Chapters 6 and 7 patterns belong to this phase
and step in ADDR. Higginbotham’s process and our patterns complement each
other here.
This page intentionally left blank
Appendix B
Implementation of the
Lakeside Mutual Case
Pattern Application
Many of the patterns from this book were applied in the Lakeside Mutual case. Some
examples follow:
1. https://github.com/Microservice-API-Patterns/LakesideMutual/blob/master/MAP.md.
463
464 Appendix B Implementation of the Lakeside Mutual Case
@RestController
@RequestMapping("/customers")
public class CustomerInformationHolder {
/**
* Returns a 'page' of customers.
*
* The query parameters {@code limit} and {@code offset} can be
* used to specify the maximum size of the page and the offset of
* the page's first customer.
*
* The response contains the customers, limit and offset of the
* current page, as well as the total number of customers
* (data set size).
* Additionally, it contains HATEOAS-style links that link to the
* endpoint addresses of the current, previous, and next page.
*/
@Operation(summary =
"Get all customers in pages of 10 entries per page.")
@GetMapping // operation responsibility: Retrieval Operation
public ResponseEntity<PaginatedCustomerResponseDto>
getCustomers(
@RequestParam(
value = "filter", required = false, defaultValue = "")
String filter,
@RequestParam(
value = "limit", required = false, defaultValue = "10")
Integer limit,
@RequestParam(
value = "offset", required = false, defaultValue = "0")
Integer offset,
@RequestParam(
value = "fields", required = false, defaultValue = "")
OpenAPI Specification and Sample API Client 465
String fields) {
PaginatedCustomerResponseDto response =
createPaginatedCustomerResponseDto(
filter,
customerPage.getLimit(),
customerPage.getOffset(),
customerPage.getSize(),
fields,
customerDtos);
return ResponseEntity.ok(response);
}
openapi: 3.0.1
info:
title: Customer Core API
description: This API allows clients to create new customers
and retrieve details about existing customers.
license:
name: Apache 2.0
version: v1.0.0
servers:
466 Appendix B Implementation of the Lakeside Mutual Case
- url: http://localhost:8110
description: Generated server url
paths:
/customers:
get:
tags:
- customer-information-holder
summary: Get all customers in pages of 10 entries per page.
operationId: getCustomers
parameters:
- name: filter
in: query
description: search terms to filter the customers by
name
required: false
schema:
type: string
default: ''
- name: limit
in: query
description: the maximum number of customers per page
required: false
schema:
type: integer
format: int32
default: 10
- name: offset
in: query
description: the offset of the page's first customer
required: false
schema:
type: integer
format: int32
default: 0
- name: fields
in: query
description: a comma-separated list of the fields
that should be included in the response
required: false
schema:
type: string
default: ''
responses:
OpenAPI Specification and Sample API Client 467
'200':
description: OK
content:
'*/*':
schema:
$ref: "#/components/schemas\
/PaginatedCustomerResponseDto"
components:
schemas:
Address:
type: object
properties:
streetAddress:
type: string
postalCode:
type: string
city:
type: string
CustomerResponseDto:
type: object
properties:
customerId:
type: string
firstname:
type: string
lastname:
type: string
birthday:
type: string
format: date-time
streetAddress:
type: string
postalCode:
type: string
city:
type: string
email:
type: string
phoneNumber:
type: string
moveHistory:
type: array
items:
468 Appendix B Implementation of the Lakeside Mutual Case
$ref: '#/components/schemas/Address'
links:
type: array
items:
$ref: '#/components/schemas/Link'
Link:
type: object
properties:
rel:
type: string
href:
type: string
AddressDto:
required:
- city
- postalCode
- streetAddress
type: object
properties:
streetAddress:
type: string
postalCode:
type: string
city:
type: string
description: the customer's new address
PaginatedCustomerResponseDto:
type: object
properties:
filter:
type: string
limit:
type: integer
format: int32
offset:
type: integer
format: int32
size:
type: integer
format: int32
customers:
OpenAPI Specification and Sample API Client 469
type: array
items:
$ref: '#/components/schemas/CustomerResponseDto'
links:
type: array
items:
$ref: '#/components/schemas/Link'
When querying the endpoint using curl, the following HTTP response is
returned:
{
"limit": 2,
"offset": 0,
"size": 50,
"customers": [ {
"customerId": "bunlo9vk5f",
"firstname": "Ado",
"lastname": "Kinnett",
"birthday": "1975-06-13T23:00:00.000+00:00",
"streetAddress": "2 Autumn Leaf Lane",
"postalCode": "6500",
"city": "Bellinzona",
"email": "[email protected]",
"phoneNumber": "055 222 4111",
"moveHistory": [ ]
}, {
"customerId": "bd91pwfepl",
"firstname": "Bel",
"lastname": "Pifford",
"birthday": "1964-02-01T23:00:00.000+00:00",
"streetAddress": "4 Sherman Parkway",
"postalCode": "1201",
"city": "Genf",
"email": "[email protected]",
"phoneNumber": "055 222 4111",
"moveHistory": [ ]
470 Appendix B Implementation of the Lakeside Mutual Case
} ],
"_links": {
"self": {
"href": "/customers?filter=&limit=2&offset=0&fields="
},
"next": {
"href": "/customers?filter=&limit=2&offset=2&fields="
}
}
}
Appendix C
Microservice Domain-Specific
Language (MDSL)
1. https://microservice-api-patterns.github.io/MDSL-Specification.
471
472 Appendix C Microservice Domain-Specific Language (MDSL)
Design Goals
As a contract language for service and API design, MDSL aims at facilitating agile
modeling practices, API sketching, and API design workshops. It is supposed to be
readable for all stakeholder groups involved in API design and evolution. MDSL
should support partial specifications that can be refined iteratively. To be usable in
tutorials and publications such as this book, its syntax must be compact so that a
nontrivial API contract still fits on one book page or presentation slide (or less).
MDSL can be used in top-down API design from requirements (for instance, user
stories for integration scenarios and API sketches) down to code and deployment
artifacts and in bottom-up discovery of internal interfaces in existing systems, possi-
bly wrapped in public, community, or solution-internal remote APIs. One example of
a top-down design process is Align-Define-Design-Refine (ADDR) [Higginbotham
2021], as introduced at the beginning of Part 2; a discovery tool with MDSL support
is the domain-driven Context Mapper [Kapferer 2021].
MDSL aims at platform independence of API designs. API Descriptions cre-
ated with MDSL are not limited to HTTP or any other single protocol or message
exchange format. The HTTP protocol design deviates from most interface definition
languages and RPC-style communication protocols in many ways. Hence, MDSL
has to provide configurable provider-to-technology bindings that surmount protocol
differences—without losing either generality or specificity.
2. https://microservice-api-patterns.github.io/MDSL-Specification/primer.
474 Appendix C Microservice Domain-Specific Language (MDSL)
MDSL Reference
Let us now walk through the language concepts in depth.
• Endpoint types define operations, which have request and (optionally) response
messages containing payload content and metadata headers. The structure of
these messages has to be specified unambiguously and agreed upon to achieve
interoperability as well as accuracy, and it must ensure a positive client devel-
oper experience.
• When certain data structures are used by multiple operations, these operations
may refer to shared data transfer representations (which are message-level pen-
dants to DTOs internal to programs). Such representations become part of
one or more API endpoint contracts.
• APIs may be used to emit and receive events. Such events also require data
definitions.
API data definitions have a strong impact on the success of an API because the
amount of coupling between client and provider is influenced by these definitions.
476 Appendix C Microservice Domain-Specific Language (MDSL)
MDSL supports data modeling in several ways, addressing the preceding usage sce-
narios. The MDSL data types are inspired—and generalize from—message exchange
formats such as JSON. Here are two examples:
The basic structure patterns from Chapter 4, Atomic Parameter and Parame-
ter Tree in particular, provide the type system of MDSL. In the example, "name":
D<string> is an Atomic Parameter, and Customer is a nested Parameter Tree,
containing an inner Parameter Tree representing one or more "address" ele-
ments. This is indicated by the asterisk * at the end of its definition.
For instance, D<int> is an integer data value and D<void> is an empty represen-
tation element.
operation createCustomer
expecting payload "customer": D
delivering payload MD
The three-part specification is a bit different from the identifier-type pairs typi-
cally used in programming languages. As stated earlier, only the role is mandatory.
This makes it possible to create rather compact specifications during agile API mod-
eling. An abstract, unspecified element can be represented as P (for parameter or
payload placeholder). P may take the place of the Role-Type elements in the Identi-
fier-Role-Type triple; the placeholder can also replace the entire triple:
operation upgradeCustomer
expecting payload "promotionCode": P // placeholder
delivering payload P // response unspecified
Multiplicity
The cardinality classifiers "*", "?", and "+" turn a type definition into a collection
("*": zero or more, "?": one or none, "+": at least one). The default, which does not
have to be specified, is "!" (exactly one).
The online language reference provides more explanations under “Data Con-
tracts and Schemas in MDSL” [Zimmermann 2022].
478 Appendix C Microservice Domain-Specific Language (MDSL)
To generate OpenAPI and, later on, server-side stubs and client-side proxies from
MDSL specifications, not all of the required binding information can be derived
from the abstract endpoint types. A particularly important example is the mapping
of MDSL operations to HTTP verbs such as GET, POST, PUT, and so on. Hence,
additional mapping details, for instance, whether a payload parameter is transferred
in the QUERY string or the message BODY (or the URI PATH or a HEADER or a
3. The protocol specifications are not fully explicit and precise here; that said, many tools and protocol
runtimes do not support this combination.
Summary of Support for Microservice API Patterns 479
COOKIE), can also be provided (as motivated earlier). Error reports and security
policies can also be bound, and media type information can be provided.
See “Protocol Bindings for HTTP, gRPC, Jolie, Java” in the online language speci-
fication for more explanations [Zimmermann 2022].
1. The basic representation elements serve as MDSL grammar rules in the data
contract part. Parameter Tree and Atomic Parameter are the main con-
structs; Atomic Parameter Lists and Parameter Forests are supported as
well. Parameter Trees correspond to JSON objects {...}; the set cardinali-
ties "*" and "+" indicate that an API that uses JSON as its message exchange
format should send or receive a JSON array [...]. Base types such as int,
string, and bool can also be found in MDSL.
2. Foundation patterns may appear as decorator annotations for the entire API
description, for instance, PUBLIC_API and FRONTEND_INTEGRATION. The
other visibility and direction patterns from Chapter 4 are supported as well:
PUBLIC_API, COMMUNITY_API, SOLUTION_INTERNAL_API.
3. Role and responsibility decorators exist on endpoint and operation levels. Some
patterns serve as decorators on the API endpoint level, for example, expressing
PROCESSING_RESOURCE and MASTER_DATA_HOLDER roles. Other responsi-
bility patterns appear as decorators representing operation responsibilities, for
instance, COMPUTATION_FUNCTION and RETRIEVAL_OPERATION (Chapter 5).
4. Representation element stereotypes provide the options for the role part of the
Identifier-Role-Type triples defining Atomic Parameters: D (data), MD (meta-
data), L (link), and ID (identifier).
5. Explicit data types and inlined representation elements can be annotated with
pattern decorators as well. Examples of stereotypes decorating representa-
tion elements are <<Context Representation>> and <<Error_Report>>
from Chapter 6 as well as <<Embedded_Entity>> and <<Wish_List>> from
Chapter 7.
480 Appendix C Microservice Domain-Specific Language (MDSL)
The following elaborate example features all five types of MAP support in MDSL:
The element role stereotypes can be combined with the base types to yield precise
specifications of Atomic Parameters.
Using the MDSL decorator annotations and stereotypes is optional. If present,
they make the API description more expressive and can be processed by tools such as
API linters/contract validators, code/configuration generators, MDSL to OpenAPI
converters, and so on.
MDSL Tools
An Eclipse-based editor and API linter, also offering transformations for rapid, goal-
driven API design (“API first”) and refactoring to many of the patterns from this
book is available. Not only can MDSL specifications be validated, but platform-
specific contracts (OpenAPI, gRPC, GraphQL, and Jolie) can be generated. A proto-
typical MDSL-Web4 tool is available as an open-source project. A command-line
interface (CLI) offers most of the IDE functionality; therefore, it is not imperative to
work with Eclipse when creating and using MDSL specifications.
An intermediate generator model and API exist so that support for other target
languages and integration with other tools can be added. Template-based reporting
is available via Apache Freemarker. One of the available sample templates turns the
MDSL into Markdown.
See “MDSL Tools: Users Guide” for updates [Zimmermann 2022].
Online Resources
The definite, up-to-date language reference can be found online.5 An MDSL primer,
a tutorial, and a quick reference are available on the MDSL Web site as well.
The Interface Refactoring Catalog introduced in Chapter 11 specifies many of its
API refactorings with before-after MDSL snippets:
https://interface-refactoring.github.io
Step-by-step instructions and demos of MDSL Tools are available as blog posts:
https://ozimmer.ch/categories/#Practices
4. https://github.com/Microservice-API-Patterns/MDSL-Web.
5. https://microservice-api-patterns.github.io/MDSL-Specification.
This page intentionally left blank
Bibliography
483
484 Bibliography
[Beck 2001] K. Beck et al., “Manifesto for Agile Software Development.” 2001.
https://agilemanifesto.org/.
[Bellido 2013] J. Bellido, R. Alarcón, and C. Pautasso, “Control-Flow Patterns for
Decentralized RESTful Service Composition.” ACM Transactions on the Web
(TWEB) 8, no. 1 (2013): 5:1–5:30. https://doi.org/10.1145/2535911.
[Belshe 2015] M. Belshe, R. Peon, and M. Thomson, “Hypertext Transfer Protocol
Version 2 (HTTP/2).” RFC 7540; RFC Editor, May 2015. https://doi.org/10.17487/
RFC7540.
[Berli 2014] W. Berli, D. Lübke, and W. Möckli, “Terravis—Large-Scale Business
Process Integration between Public and Private Partners.” In Proceedings of
INFORMATIK 2014, Gesellschaft für Informatik e.V., 2014, 1075–1090.
[Beyer 2016] B. Beyer, C. Jones, J. Petoff, and N. R. Murphy, Site Reliability
Engineering: How Google Runs Production Systems. O’Reilly, 2016.
[Bishop 2021] M. Bishop, “Level 3 REST.” Draft, 2021. https://level3.rest/.
[Borysov 2021] A. Borysov and R. Gardiner, “Practical API Design at Netflix,
Part 1: Using Protobuf FieldMask.” Netflix Technology Blog, 2021. https://
netflixtechblog.com/practical-api-design-at-netflix-part-1-using-protobuf-
fieldmask-35cfdc606518.
[Brewer 2012] E. Brewer, “CAP Twelve Years Later: How the ‘Rules’ Have Changed.”
Computer 45, no. 2 (2012): 23–29.
[Brown 2021] K. Brown, B. Woolf, C. D. Groot, C. Hay, and J. Yoder, “Patterns
for Developers and Architects Building for the Cloud.” Accessed June 24, 2022.
https://kgb1001001.github.io/cloudadoptionpatterns/.
[Buschmann 1996] F. Buschmann, R. Meunier, H. Rohnert, P. Sommerlad, and M.
Stal, Pattern-Oriented Software Architecture—Volume 1: A System of Patterns.
Wiley, 1996.
[Buschmann 2007] F. Buschmann, K. Henney, and D. Schmidt, Pattern-Oriented
Software Architecture: A Pattern Language for Distributed Computing. Wiley,
2007.
[Cavalcante 2019] A. Cavalcante, “What Is DX?” October 2019. https://medium.
com/swlh/what-is-dx-developer-experience-401a0e44a9d9.
[Cervantes 2016] H. Cervantes and R. Kazman, Designing Software Architectures: A
Practical Approach. Addison-Wesley, 2016.
[Cisco Systems 2015] “API Design Guide.” Cisco DevNet, 2015. https://github.com/
CiscoDevNet/api-design-guide.
[Coplien 1997] J. O. Coplien and B. Woolf, “A Pattern Language for Writers’
Workshops.” C Plus Plus Report 9 (1997): 51–60.
[C-SIG 2014] C-SIG, “Cloud Service Level Agreement Standardisation Guidelines.”
Cloud Select Industry Group, Service Level Agreements Subgroup; European
Commission, 2014. https://ec.europa.eu/newsroom/dae/redirection/document/
6138.
[Daigneau 2011] R. Daigneau, Service Design Patterns: Fundamental Design
Solutions for SOAP/WSDL and RESTful Web Services. Addison-Wesley, 2011.
Bibliography 485
[JSON API 2022] JSON API, “JSON:API: A Specification for Building APIs in
JSON.” 2022. https://jsonapi.org/.
[Judkowitz 2018] J. Judkowitz and M. Carter, “SRE Fundamentals: SLIs, SLAs and
SLOs.” Google Cloud Platform Blog, 2018. https://cloudplatform.googleblog.
com/2018/07/sre-fundamentals-slis-slas-and-slos.html?m=1.
[Julisch 2011] K. Julisch, C. Suter, T. Woitalla, and O. Zimmermann, “Compliance
by Design–Bridging the Chasm between Auditors and IT Architects.” Computers
& Security 30, no. 6 (2011): 410–426.
[Kapferer 2021] S. Kapferer and O. Zimmermann, “ContextMapper: A Modeling
Framework for Strategic Domain-Driven Design.” Context Mapper, 2021. https://
contextmapper.org/.
[Kelly 2016] M. Kelly, “JSON Hypertext Application Language.” Internet
Engineering Task Force; Internet Engineering Task Force, Internet-Draft, May
2016. https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-08.
[Kerievsky 2004] J. Kerievsky, Refactoring to Patterns. Pearson Higher Education,
2004.
[Kimball 2002] R. Kimball and M. Ross, The Data Warehouse Toolkit: The Complete
Guide to Dimensional Modeling, 2nd ed. Wiley, 2002.
[Kircher 2004] M. Kircher and P. Jain, Pattern-Oriented Software Architecture,
Volume 3: Patterns for Resource Management. Wiley, 2004.
[Klabnik 2011] S. Klabnik, “Nobody Understands REST or HTTP.” 2011. https://
steveklabnik.com/writing/nobody-understands-rest-or-http#representations.
[Knoche 2019] H. Knoche, “Improving Batch Performance When Migrating to
Microservices with Chunking and Coroutines.” Softwaretechnik-Trends 39, no.
4 (2019): 20–22.
[Krafzig 2004] D. Krafzig, K. Banke, and D. Slama, Enterprise SOA: Service-Oriented
Architecture Best Practices (the COAD Series). Prentice Hall, 2004.
[Kruchten 2000] P. Kruchten, The Rational Unified Process: An Introduction, 2nd ed.
Addison-Wesley, 2000.
[Kruchten 2013] P. Kruchten, “Contextualizing Agile Software Development.”
Journal of Software: Evolution and Process 25, no. 4 (2013): 351–361. https://doi.
org/10.1002/smr.572.
[Kubernetes 2022] Kubernetes, “The Kubernetes API.” Accessed June 24, 2022.
https://kubernetes.io/docs/concepts/overview/kubernetes-api/.
[Lanthaler 2021] M. Lanthaler, “Hydra Core Vocabulary—A Vocabulary for
Hypermedia-Driven Web APIs.” Unofficial draft, July 2021. http://www.hydra-cg.
com/spec/latest/core/.
[Lauret 2017] A. Lauret, “API Stylebook: Collections of Resources for API designers.”
2017. http://apistylebook.com/.
[Lauret 2019] A. Lauret, The Design of Web APIs. Manning, 2019.
[Leach 2005] P. J. Leach, R. Salz, and M. H. Mealling, “A Universally Unique
IDentifier (UUID) URN Namespace.” RFC 4122; RFC Editor, July 2005. https://
doi.org/10.17487/RFC4122.
490 Bibliography
[OWASP 2021] “OWASP REST Security Cheat Sheet.” OWASP Cheat Sheet Series,
2021. https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_
Sheet.html.
[Pardon 2011] G. Pardon and C. Pautasso, “Towards Distributed Atomic
Transactions over RESTful Services.” In REST: From Research to Practice, edited
by E. Wilde and C. Pautasso. Springer, 2011, 507–524.
[Pardon 2018] G. Pardon, C. Pautasso, and O. Zimmermann, “Consistent Disaster
Recovery for Microservices: The BAC theorem.” IEEE Cloud Computing 5, no. 1
(2018): 49–59. https://doi.org/10.1109/MCC.2018.011791714.
[Pautasso 2016] C. Pautasso, A. Ivanchikj, and S. Schreier, “A Pattern Language for
RESTful Conversations.” In Proceedings of the 21st European Conference on
Pattern Languages of Programs. Association for Computing Machinery, 2016.
[Pautasso 2017a] C. Pautasso, O. Zimmermann, M. Amundsen, J. Lewis, and N. M.
Josuttis, “Microservices in Practice, Part 1: Reality Check and Service Design.”
IEEE Software 34, no. 1 (2017): 91–98. https://doi.org/10.1109/MS.2017.24.
[Pautasso 2017b] C. Pautasso, O. Zimmermann, M. Amundsen, J. Lewis, and
N. M. Josuttis, “Microservices in Practice, Part 2: Service Integration and
Sustainability.” IEEE Software 34, no. 2 (2017): 97–104. https://doi.org/10.1109/
MS.2017.56.
[Pautasso 2018] C. Pautasso and O. Zimmermann, “The Web as a Software
Connector: Integration Resting on Linked Resources.” IEEE Software 35, no. 1
(2018): 93–98. https://doi.org/10.1109/MS.2017.4541049.
[Preston-Werner 2021] T. Preston-Werner, “Semantic Versioning 2.0.0.” 2021.
https://semver.org/.
[Reschke 2015] J. Reschke, “The ‘Basic’ HTTP Authentication Scheme.” RFC 7617;
RFC Editor, September 2015. https://doi.org/10.17487/RFC7617.
[Richardson 2016] C. Richardson, “Microservice Architecture.” Microservices.io,
2016, http://microservices.io.
[Richardson 2018] C. Richardson, Microservices Patterns. Manning, 2018.
[Richardson 2019] C. Richardson, “Documenting a Service Using the Microservice
Canvas,” Chris Richardson Consulting Blog, 2019, https://chrisrichardson.net/
post/microservices/general/2019/02/27/microservice-canvas.html.
[Riley 2017] J. Riley, Understanding Metadata: What Is Metadata, and What Is It
For? A Primer. NISO, 2017. https://www.niso.org/publications/understanding-
metadata-2017.
[Rosenberg 2002] M. Rosenberg, Nonviolent Communication: A Language of Life.
PuddleDancer Press, 2002.
[Rozanski 2005] N. Rozanski and E. Woods, Software Systems Architecture: Working
with Stakeholders Using Viewpoints and Perspectives. Addison-Wesley, 2005.
[Ruby on Rails 2022] Ruby on Rails Web site. Accessed June 24, 2022. https://
rubyonrails.org/.
Bibliography 493
[Wilde 2013] E. Wilde, “The ‘profile’ Link Relation Type.” RFC 6906; RFC Editor,
March 2013. https://doi.org/10.17487/RFC6906.
[Wirfs-Brock 2002] R. Wirfs-Brock and A. McKean, Object Design: Roles,
Responsibilities, and Collaborations. Pearson Education, 2002.
[Wirfs-Brock 2011] “Agile Architecture Myths #2 Architecture Decisions Should Be
Made at the Last Responsible Moment” (posted by Rebecca). wirfs-brock.com,
January 18, 2011. http://wirfs-brock.com/blog/2011/01/18/agile-architecture-myths-
2-architecture-decisions-should-be-made-at-the-last-responsible-moment/.
[Wirfs-Brock 2019] R. Wirfs-Brock, “Cultivating Your Design Heuristics.” Online
slide deck, wirfs-brock.com, 2019. https://de.slideshare.net/rwirfs-brock/
cultivating-your-design-heuristics.
[Yalon 2019] E. Yalon and I. Shkedy, “OWASP API Security Project.” OWASP
Foundation, 2019. https://owasp.org/www-project-api-security/.
[Zalando 2021] Zalando, “RESTful API and Event Guidelines.” Zalando SE
Opensource, 2021. https://opensource.zalando.com/restful-api-guidelines.
[Zdun 2013] U. Zdun, R. Capilla, H. Tran, and O. Zimmermann, “Sustainable
Architectural Design Decisions.” IEEE Software 30, no. 6 (2013): 46–53. https://
doi.org/10.1109/MS.2013.97.
[Zdun 2018] U. Zdun, M. Stocker, O. Zimmermann, C. Pautasso, and D. Lübke,
“Guiding Architectural Decision Making on Quality Aspects in Microservice
APIs.” In Service-Oriented Computing: 16th International Conference, ICSOC
2018, Hangzhou, China, November 12–15, 2018, Proceedings. Springer, 2018,
73–89. https://doi.org/10.1007/978-3-030-03596-9_5.
[Zdun 2020] U. Zdun, E. Wittern, and P. Leitner, “Emerging Trends, Challenges, and
Experiences in DevOps and Microservice APIs.” IEEE Software 37, no. 1 (2020):
87–91. https://doi.org/10.1109/MS.2019.2947982.
[Zeng 2015] M. L. Zeng, Metadata Basics Web site. 2015. https://www.metadataetc.
org/metadatabasics/types.htm.
[Zimmermann 2003] O. Zimmermann, M. Tomlinson, and S. Peuser, Perspectives
on Web Services: Applying SOAP, WSDL and UDDI to Real-World Projects.
Springer, 2003.
[Zimmermann 2004] O. Zimmermann, P. Krogdahl, and C. Gee, “Elements of Service-
Oriented Analysis and Design.” Developer Works, IBM Corporation. 2004.
[Zimmermann 2007] O. Zimmermann, J. Grundler, S. Tai, and F. Leymann,
“Architectural Decisions and Patterns for Transactional Workflows in SOA.” In
Proceedings of the Fifth International Conference on Service-Oriented Computing
(ICSOC). Springer-Verlag, 2007, 81–93. https://doi.org/10.1007/978-3-540-74974-5.
[Zimmermann 2009] O. Zimmermann, “An Architectural Decision Modeling
Framework for Service-Oriented Architecture Design.” PhD thesis, University of
Stuttgart, Germany, 2009. http://elib.uni-stuttgart.de/opus/volltexte/2010/5228/.
[Zimmermann 2015] O. Zimmermann, “Architectural Refactoring: A Task-Centric
View on Software Evolution.” IEEE Software 32, no. 2 (2015): 26–29. https://doi.
org/10.1109/MS.2015.37.
Bibliography 497
499
500 Index
Frontend Integration, 138–139 infrastructure, 13, 97, 205, 239, 284, 295, 313,
Public API, 142–143 323, 335, 343, 344, 347, 354, 433, 436
Solution-Internal API, 144–145 integration, 427–428, 429–430, 437, 441,
frontend, 4, 10, 31, 36–37, 38, 47, 52, 53, 138, 447, 450, 6–8, 12, 16, 18–19, 22, 28,
140, 145–146, 228, 229, 232–233, 235, 47, 128, 140, 141, 142, 145, 170, 174,
236, 237, 281, 317, 333, 368 177–178, 212, 217–218, 227, 236, 258,
Frontend Integration pattern, 53, 138–139 266, 269, 275, 276, 367–368, 388, 426
function, API, 21 integration types, decisions, 52
future of APIs, 450 Backend Integration pattern, 53–55
Frontend Integration pattern, 53
interface. See API(s), local
G Internet of Things, 14
gateway, 97, 236, 298, 303, 305, 319, 335, 340, interoperability, 54, 56–57, 76–77, 141
404, 411, 449
GET requests, 322–323 J-K
GitHub, 5, 414
Google JavaScript, 10, 37
Maps, 15 JSON, 128, 153–154
Quantum AI, 14 Kerberos, 87, 287, 306–307
governance, API quality, 84–85, 98, 114, 377 Kubernetes, 11, 450
GraphQL, 339, 343
GUID, 276
L
H Lakeside Mutual, 31
API design and target specification, 39–41
handling of referenced data decisions, 107–108 business context and requirements, 31–32
Embedded Entity pattern, 108 cursor-based pagination, 331
Linked Information Holder pattern, 109 CustomerInformationHolder controller,
Helland, P., “Data on the Outside versus Data 82–83
on the Inside”, 405 domain model, 32–35
hiding shared data structures behind domain microservices architecture, 38
logic, 176–178 offset-based pagination, 330–331
home resource, 23 quality and evolution patterns, 120–122
HTTP (Hyper-text Transfer Protocol) self-service features
APIs, 6 application architecture, 36–38
long polling, 352 current system, 35–36
hypermedia-oriented protocols, 6 desired qualities, 31–32
usability, 32
I user stories and desired qualities, 32
library, 246–247
IBANs, 382–383 lifetime, 16
ID Element pattern, 81, 271–274, 275, 276 Limited Lifetime Guarantee pattern,
IDEAL (Isolated State, Distribution, Elasticity 115–116, 361, 385, 385–386, 387–388
Automation and Loose Coupling), Link Element pattern, 81–82, 276–279, 280,
10–11, 12 280–282
idempotence, 164 Link Lookup Resource pattern, 64–65,
Information Holder Resource pattern, 200–206
60–63, 176–182, 183 Linked Information Holder pattern, 109,
129, 311, 320, 321–324, 325
504 Index
provider-side processing, 57, 168–170, 201 representation element, 19, 25–26, 30, 79, 80,
pubishing an API, 18 81, 128, 133, 150, 152, 158, 258–259,
Public API pattern, 48–49, 142–143 263, 263, 264, 265, 305–306, 367,
Published Language, 51, 201, 255, 258, 260, 380–381, 465
262, 265 flat versus nested structure, 71–78
Request Bundle pattern, 104–105, 311–312,
Q 351–353, 354, 355
request pagination, 334
QoS (quality of service), 84, 416–418 request-reply message, 24, 336
quality, 309–310 resale software ecosystems, 13
attributes, 8, 29 resource, 23, 60, 61, 64–65, 76, 105, 266, 322,
governing, 84–85 323, 408. See also Data Transfer
role- and responsibility-driven API Resource pattern; Information
design, 163–164 Holder Resource pattern; Link
challenges of improving, 310–311
Lookup Resource pattern; Processing
Lakeside Mutual, patterns, 120–122
Resource pattern
objectives and penalties, 92–93
response message, 24
pagination decisions, 98–102
response shaping, 338
quantum computing, 14
response slicing, 326, 327, 332
Query component, Terravis, 432–433
response time. See performance
queue-based, message-oriented application
Responsibility, 57, 66, 82, 162
integration, 5
REST (Representational State Transfer), 6
Retrieval Operation pattern, 68, 222–223,
R 224–228
Rate Limit pattern, 90–92, 411–415 role- and responsibility-driven API design,
real-world API designs challenges and desired qualities,
retrospective and outlook, 444 163–164
SACAC role stereotype, 182–183, 215
business context and domain, 438–439 roles and responsibilities, 248
pattern usage and implementation, decisions, 57–59, 61, 66
442–443 Data Transfer Resource pattern,
role and status of API, 440–441 65–66
technical challenges, 439–440 Information Holder Resources
Terravis pattern, 60–63
business context and domain, 426–433 Link Lookup Resource pattern, 64–65
pattern usage and implementation, Master Data Holder pattern, 63–64
429–436 Operational Data Holder pattern,
role and status of API, 429 63–64
technical challenges, 427–428 Processing Resource pattern, 60
refactoring, 77, 200, 385, 431, 449–450 Reference Data Holder pattern, 64
reference data, 62, 64, 178–179, 195–200, 313 operation responsibility, 66–70
Reference Data Holder pattern, 64, Computation Function pattern, 69
195–200 Retrieval Operation pattern, 68
relationship, 27–28, 36, 73, 108, 152, 176–177, State Creation Operations pattern,
178–179, 181, 182–183, 184–185, 190, 67–68
191, 260, 276, 315–317, 318, 320, 322 State Transition Operation pattern,
relationship holder resource, 322 68–69
remote API, 4–5, 7, 8, 28–29, 447, 448, RPC (Remote Procedure Call), 5
remote facade, 188, 194, 195 Ruby on Rails, 443
Index 507