0% found this document useful (0 votes)
1K views545 pages

AW Patterns For API Design

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1K views545 pages

AW Patterns For API Design

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 545

“APIs are eating the world.

Organizations and collaborations are depending more and


more on APIs. For all these APIs to be designed, using patterns is a well-established way
of tackling design challenges. Patterns for API Design helps practitioners to design
their APIs more effectively: They can focus on designing their application domain
while standard design issues are solved with patterns. If you’re working in the API
space, this book will change how you design APIs and how you look at APIs.”

—Erik Wilde, Catalyst at Axway

“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.”

—Eoin Woods, CTO, Endava

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.”

—Rick Kazman, University of Hawaii

“Finally, the important topic of API design is addressed systematically! I wish I


would have had this great pattern collection a few years earlier.”
—Dr. Gernot Starke, INNOQ Fellow

“I observed software projects fail because middleware technology hid a system’s


distributed nature from programmers. They designed problematic APIs of a non-
distributed gestalt exercised remotely. This book embraces the required dispersal of
software in an interdependent world and provides timeless advice on designing inter-
faces between its separated parts. The Patterns guide beyond specific middleware
technology and will not only help with creation and understanding but also with
necessary evolution of the interconnected software systems we grow today and in the
future. Those systems not only span the globe for international business, but also
work within our cars, houses, and almost any technology our daily lives depend on.”

—Peter Sommerlad, independent consultant, author of


Pattern-Oriented Software Architecture: A System of Patterns and Security Patterns

“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.”

—Dr. Uwe van Heesch, Practicing Software Architect and


Former Vice President Hillside Europe
“This comprehensive collection of API patterns is an invaluable resource for soft-
ware engineers and architects designing interoperable software systems. The intro-
duction into API fundamentals and numerous case study examples make it excellent
teaching material for future software engineers. Many of the patterns discussed in
this book are extremely useful in practice and were applied to design the APIs of
integrated, mission-critical rail operations centre systems.”

—Andrei Furda, Senior Software Engineer at Hitachi Rail STS Australia


This page intentionally left blank
Patterns for API Design
Pearson Addison-Wesley
Signature Series

Visit informit.com/awss/vernon for a complete list of available publications.

The Pearson Addison-Wesley Signature Series provides readers with


practical and authoritative information on the latest trends in modern
technology for computer professionals. The series is based on one
simple premise: great books come from great authors.

Vaughn Vernon is a champion of simplifying software architecture and


development, with an emphasis on reactive methods. He has a unique
ability to teach and lead with Domain-Driven Design using lightweight
tools to unveil unimagined value. He helps organizations achieve
competitive advantages using enduring tools such as architectures,
patterns, and approaches, and through partnerships between business
stakeholders and software developers.

Vaughn’s Signature Series guides readers toward advances in software


development maturity and greater success with business-centric
practices. The series emphasizes organic refinement with a variety
of approaches—reactive, object, and functional architecture and
programming; domain modeling; right-sized services; patterns; and
APIs—and covers best uses of the associated underlying technologies.

Make sure to connect with us!


informit.com/socialconnect
Patterns for API
Design
Simplifying Integration with Loosely
Coupled Message Exchanges

Olaf Zimmermann
Mirko Stocker
Daniel Lübke
Uwe Zdun
Cesare Pautasso

Boston • Columbus • New York • San Francisco • Amsterdam • Cape Town


Dubai • London • Madrid • Milan • Munich • Paris • Montreal • Toronto • Delhi • Mexico City
São Paulo • Sydney • Hong Kong • Seoul • Singapore • Taipei • Tokyo
Cover image: Joshua Small-Photographer / Shutterstock

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 government sales inquiries, please contact [email protected].

For questions about sales outside the U.S., please contact [email protected].

Visit us on the Web: informit.com

Library of Congress Control Number: 2022947404

Copyright © 2023 Pearson Education, Inc.

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:

• Everyone has an equitable and lifelong opportunity to succeed through learning.


• Our educational products and services are inclusive and represent the rich diversity of
learners.
• Our educational content accurately reflects the histories and experiences of the learners we
serve.
• Our educational content prompts deeper discussions with learners and motivates them to
expand their own learning (and worldview).

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.

• Please contact us with concerns about any potential bias at https://www.pearson.com/


report-bias.html.
This page intentionally left blank
Contents

Foreword by Vaughn Vernon, Series Editor . . . . . . . . . . . . . . . . . . . . . . . . xvii


Foreword by Frank Leymann . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiii
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxiii
About the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxv

Part 1: Foundations and Narratives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

Chapter 1: Application Programming Interface (API) Fundamentals . . . . . . . 3


From Local Interfaces to Remote APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
A Bit of Distribution and Remoting History . . . . . . . . . . . . . . . . . 5
Remote API: Access to Services via Protocol for Integration. . . . . 6
APIs Matter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Decision Drivers in API Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
What Makes an API Successful? . . . . . . . . . . . . . . . . . . . . . . . . . 15
How Do API Designs Differ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
What Makes API Design Challenging? . . . . . . . . . . . . . . . . . . . . 17
Architecturally Significant Requirements . . . . . . . . . . . . . . . . . . 19
Developer Experience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
A Domain Model for Remote APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Communication Participants . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Endpoints Offer Contracts Describing Operations . . . . . . . . . . . 24
Messages as Conversation Building Blocks . . . . . . . . . . . . . . . . . 24
Message Structure and Representation . . . . . . . . . . . . . . . . . . . . 25
API Contract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Domain Model Usage throughout the Book . . . . . . . . . . . . . . . . 27
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Chapter 2: Lakeside Mutual Case Study . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Business Context and Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
User Stories and Desired Qualities . . . . . . . . . . . . . . . . . . . . . . . 32

xi
xii Contents

Analysis-Level Domain Model . . . . . . . . . . . . . . . . . . . . . . . . . . 32


Architecture Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
System Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Application Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
API Design Activities. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Target API Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Chapter 3: API Decision Narratives. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Prelude: Patterns as Decision Options, Forces as Decision Criteria . . . . 43
Foundational API Decisions and Patterns . . . . . . . . . . . . . . . . . . . . . . . . 45
API Visibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
API Integration Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Documentation of the API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Decisions about API Roles and Responsibilities . . . . . . . . . . . . . . . . . . . 57
Architectural Role of an Endpoint . . . . . . . . . . . . . . . . . . . . . . . 59
Refining Information Holder Roles . . . . . . . . . . . . . . . . . . . . . . . 61
Defining Operation Responsibilities . . . . . . . . . . . . . . . . . . . . . . 66
Selecting Message Representation Patterns . . . . . . . . . . . . . . . . . . . . . . . 70
Flat versus Nested Structure of Representation Elements . . . . . . 71
Element Stereotypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Interlude: Responsibility and Structure Patterns in the
Lakeside Mutual Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Governing API Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Identification and Authentication of the API Client . . . . . . . . . . 85
Metering and Charging for API Consumption . . . . . . . . . . . . . . 88
Preventing API Clients from Excessive API Usage . . . . . . . . . . . . 90
Explicit Specification of Quality Objectives and Penalties . . . . . 92
Communication of Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Explicit Context Representation . . . . . . . . . . . . . . . . . . . . . . . . . 96
Deciding for API Quality Improvements . . . . . . . . . . . . . . . . . . . . . . . . . 98
Pagination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Other Means of Avoiding Unnecessary Data Transfer . . . . . . . 102
Handling Referenced Data in Messages . . . . . . . . . . . . . . . . . . 107
Decisions about API Evolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Versioning and Compatibility Management . . . . . . . . . . . . . . . 112
Strategies for Commissioning and Decommissioning . . . . . . . . 115
Contents xiii

Interlude: Quality and Evolution Patterns in the


Lakeside Mutual Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Part 2: The Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

Chapter 4: Pattern Language Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 127


Positioning and Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Patterns: Why and How? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Navigating through the Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Structural Organization: Find Patterns by Scope . . . . . . . . . . . 131
Theme Categorization: Search for Topics . . . . . . . . . . . . . . . . . 132
Time Dimension: Follow Design Refinement Phases . . . . . . . . 135
How to Navigate: The Map to MAP . . . . . . . . . . . . . . . . . . . . . 136
Foundations: API Visibility and Integration Types . . . . . . . . . . . . . . . . 137
Pattern: Frontend Integration . . . . . . . . . . . . . . . . . . . . . . . . 138
Pattern: Backend Integration . . . . . . . . . . . . . . . . . . . . . . . . . 139
Pattern: Public API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Pattern: Community API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Pattern: Solution-Internal API . . . . . . . . . . . . . . . . . . . . . . . . 144
Foundation Patterns Summary . . . . . . . . . . . . . . . . . . . . . . . . . 145
Basic Structure Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Pattern: Atomic Parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Pattern: Atomic Parameter List . . . . . . . . . . . . . . . . . . . . . . . . 150
Pattern: Parameter Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Pattern: Parameter Forest. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Basic Structure Patterns Summary . . . . . . . . . . . . . . . . . . . . . . 157
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Chapter 5: Define Endpoint Types and Operations . . . . . . . . . . . . . . . . . . 161
Introduction to API Roles and Responsibilities. . . . . . . . . . . . . . . . . . . 162
Challenges and Desired Qualities . . . . . . . . . . . . . . . . . . . . . . . 163
Patterns in this Chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Endpoint Roles (aka Service Granularity) . . . . . . . . . . . . . . . . . . . . . . . 167
Pattern: Processing Resource . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Pattern: Information Holder Resource . . . . . . . . . . . . . . . . . 176
Pattern: Operational Data Holder . . . . . . . . . . . . . . . . . . . . . 183
Pattern: Master Data Holder. . . . . . . . . . . . . . . . . . . . . . . . . . 190
xiv Contents

Pattern: Reference Data Holder . . . . . . . . . . . . . . . . . . . . . . . 195


Pattern: Link Lookup Resource . . . . . . . . . . . . . . . . . . . . . . . . . 200
Pattern: Data Transfer Resource . . . . . . . . . . . . . . . . . . . . . . . 206
Operation Responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Pattern: State Creation Operation . . . . . . . . . . . . . . . . . . . . . 216
Pattern: Retrieval Operation . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Pattern: State Transition Operation . . . . . . . . . . . . . . . . . . . . 228
Pattern: Computation Function . . . . . . . . . . . . . . . . . . . . . . . . 240
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
Chapter 6: Design Request and Response Message Representations . . . . . 253
Introduction to Message Representation Design . . . . . . . . . . . . . . . . . 253
Challenges When Designing Message Representations . . . . . . 254
Patterns in this Chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Element Stereotypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Pattern: Data Element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Pattern: Metadata Element . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Pattern: Id Element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
Pattern: Link Element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
Special-Purpose Representations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
Pattern:API Key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
Pattern: Error Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
Pattern: Context Representation . . . . . . . . . . . . . . . . . . . . . . 293
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
Chapter 7: Refine Message Design for Quality . . . . . . . . . . . . . . . . . . . . . 309
Introduction to API Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Challenges When Improving API Quality . . . . . . . . . . . . . . . . . 310
Patterns in This Chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Message Granularity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Pattern: Embedded Entity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Pattern: Linked Information Holder . . . . . . . . . . . . . . . . . . . 320
Client-Driven Message Content (aka Response Shaping) . . . . . . . . . . . 325
Pattern: Pagination. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
Pattern: Wish List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
Pattern: Wish Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
Contents xv

Message Exchange Optimization (aka Conversation Efficiency) . . . . . 344


Pattern: Conditional Request . . . . . . . . . . . . . . . . . . . . . . . . . 345
Pattern: Request Bundle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
Chapter 8: Evolve APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
Introduction to API Evolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
Challenges When Evolving APIs . . . . . . . . . . . . . . . . . . . . . . . . 358
Patterns in This Chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
Versioning and Compatibility Management . . . . . . . . . . . . . . . . . . . . . 362
Pattern: Version Identifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Pattern: Semantic Versioning . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Life-Cycle Management Guarantees . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
Pattern: Experimental Preview. . . . . . . . . . . . . . . . . . . . . . . . . 375
Pattern: Aggressive Obsolescence . . . . . . . . . . . . . . . . . . . . . . 379
Pattern:Limited Lifetime Guarantee . . . . . . . . . . . . . . . . . . . . 385
Pattern: Two in Production. . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Chapter 9: Document and Communicate API Contracts . . . . . . . . . . . . . . 395
Introduction to API Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
Challenges When Documenting APIs . . . . . . . . . . . . . . . . . . . . 396
Patterns in This Chapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
Documentation Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
Pattern: API Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
Pattern: Pricing Plan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
Pattern: Rate Limit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
Pattern: Service Level Agreement . . . . . . . . . . . . . . . . . . . . . . 416
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Part 3: Our Patterns in Action (Now and Then) . . . . . . . . . . . . . . . . . . . . 423

Chapter 10: Real-World Pattern Stories . . . . . . . . . . . . . . . . . . . . . . . . . . . 425


Large-Scale Process Integration in the Swiss Mortgage Business . . . . . 426
Business Context and Domain . . . . . . . . . . . . . . . . . . . . . . . . . 426
Technical Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
Role and Status of API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
Pattern Usage and Implementation . . . . . . . . . . . . . . . . . . . . . . 429
Retrospective and Outlook . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
Offering and Ordering Processes in Building Construction . . . . . . . . . 438
Business Context and Domain . . . . . . . . . . . . . . . . . . . . . . . . . 438
Technical Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
Role and Status of API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
Pattern Usage and Implementation . . . . . . . . . . . . . . . . . . . . . . 442
Retrospective and Outlook . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
Chapter 11: Conclusion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
Short Retrospective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
API Research: Refactoring to Patterns, MDSL, and More . . . . . . . . . . 449
The Future of APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Additional Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
Final Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
Appendix A: Endpoint Identification and Pattern Selection Guides. . . . . . . 453

Appendix B: Implementation of the Lakeside Mutual Case . . . . . . . . . . . . 463

Appendix C: Microservice Domain-Specific Language (MDSL) . . . . . . . . . 471

Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499
Foreword by Vaughn Vernon,
Series Editor

My signature series emphasizes organic growth and refinement, which I describe in


more detail below. It only makes sense to start off by describing the organic commu-
nication that I experienced with the first author of this book, Professor Dr. Olaf
Zimmermann.
As I often refer to Conway’s Law of system design, communication is a critical fac-
tor in software development. Systems designs not only resemble the communication
structures of the designers; the structure and assembling of individuals as communica-
tors is just as important. It can lead from interesting conversations to stimulating
thoughts and continue to deliver innovative products. Olaf and I met at a Java User
Group meeting in Bern, Switzerland, in November 2019. I gave a talk on reactive archi-
tecture and programming and how it is used with Domain-Driven Design. Afterward,
Olaf introduced himself. I also met his graduate student and later colleague, Stefan
Kapferer. Together they had organically designed and built the open-source product
Context Mapper (a domain-specific language and tools for Domain-Driven Design).
Our chance meeting ultimately led to this book’s publication. I’ll tell more of this story
after I describe the motivation and purpose of my book series.
My Signature Series is designed and curated to guide readers toward advances in
software development maturity and greater success with business-centric practices.
The series emphasizes organic refinement with a variety of approaches—reactive,
object, as well as functional architecture and programming; domain modeling; right-
sized services; patterns; and APIs—and covers best uses of the associated underlying
technologies.
From here, I am focusing now on only two words: organic refinement.
The first word, organic, stood out to me recently when a friend and colleague
used it to describe software architecture. I have heard and used the word organic in
connection with software development, but I didn’t think about that word as care-
fully as I did then when I personally consumed the two used together: organic
architecture.
Think about the word organic, and even the word organism. For the most part,
these are used when referring to living things, but they are also used to describe inan-
imate things that feature some characteristics that resemble life forms. Organic

xvii
xviii Foreword by Vaughn Vernon, Series Editor

originates in Greek. Its etymology is with reference to a functioning organ of the


body. If you read the etymology of organ, it has a broader use, and in fact organic
followed suit: body organs; to implement; describes a tool for making or doing; a
musical instrument.
We can readily think of numerous organic objects—living organisms—from the
very large to the microscopic single-celled life forms. With the second use of organ-
ism, though, examples may not as readily pop into our mind. One example is an
organization, which includes the prefix of both organic and organism. In this use of
organism, I’m describing something that is structured with bidirectional dependen-
cies. An organization is an organism because it has organized parts. This kind of
organism cannot survive without the parts, and the parts cannot survive without the
organism.
Taking that perspective, we can continue applying this thinking to nonliving
things because they exhibit characteristics of living organisms. Consider the atom.
Every single atom is a system unto itself, and all living things are composed of atoms.
Yet, atoms are inorganic and do not reproduce. Even so, it’s not difficult to think of
atoms as living things in the sense that they are endlessly moving, functioning. Atoms
even bond with other atoms. When this occurs, each atom is not only a single system
unto itself, but becomes a subsystem along with other atoms as subsystems, with
their combined behaviors yielding a greater whole system.
So then, all kinds of concepts regarding software are quite organic in that nonliv-
ing things are still “characterized” by aspects of living organisms. When we discuss
software model concepts using concrete scenarios, or draw an architecture diagram,
or write a unit test and its corresponding domain model unit, software starts to come
alive. It isn’t static because we continue to discuss how to make it better, subjecting it
to refinement, where one scenario leads to another, and that has an impact on the
architecture and the domain model. As we continue to iterate, the increasing value in
refinements leads to incremental growth of the organism. As time progresses, so
does the software. We wrangle with and tackle complexity through useful abstrac-
tions, and the software grows and changes shapes, all with the explicit purpose of
making work better for real, living organisms at global scales.
Sadly, software organics tend to grow poorly more often than they grow well. Even
if they start out life in good health, they tend to get diseases, become deformed, grow
unnatural appendages, atrophy, and deteriorate. Worse still is that these symptoms are
caused by efforts to refine the software that go wrong instead of making things better.
The worst part is that with every failed refinement, everything that goes wrong with
these complexly ill bodies doesn’t cause their death. Oh, if they could just die! Instead,
we have to kill them and killing them requires nerves, skills, and the intestinal fortitude
of a dragon slayer. No, not one, but dozens of vigorous dragon slayers. Actually, make
that dozens of dragon slayers who have really big brains.
Foreword by Vaughn Vernon, Series Editor xix

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.

—Prof. Dr. Dr. h. c. Frank Leymann, Managing Director


Institute of Architecture of Application Systems
University of Stuttgart
Preface

This introduction to our book covers the following:

• 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:

• Application frontends, such as mobile apps on smartphones, place requests


for transaction processing at their backends, such as purchase orders in online
shops.
• Application parts exchange long-lived data such as customer profiles or product
catalogs with each other and with the systems of business partners, customers,
and suppliers.
• Application backends provide external services such as payment gateways or
cloud storage with data and metadata.

The software components involved in these scenarios—large, small, and


in-between—talk to others to achieve their individual goals while jointly serving end
users. The software engineer’s response to this distribution challenge is application
integration via application programming interfaces (APIs). Every integration
scenario involves at least two communication parties: API client and API provider.

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).

Goals and Scope


Our mission is to help overcome the complexity of designing and evolving APIs
through proven, reusable solution elements:

How can APIs be engineered understandably and sustainably, starting from


stakeholder goals, architecturally significant requirements, and already
proven design elements?

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

• How is loose coupling of API operations and client-provider interactions ensured?


• What are suitable message representations: flat or hierarchically nested ones?
How is agreement reached on the meaning of the representation elements so
that these elements are processed correctly and efficiently?
• Should API providers be responsible for processing data provided by their cli-
ents, possibly changing the provider-side state and connecting to backend sys-
tems? Or should they merely provide shared data stores to their clients?
• How are changes to APIs introduced in a controlled way that balances extensi-
bility and compatibility?

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.

Existing Design Heuristics (and Knowledge Gaps)


You can find many excellent books that provide deep advice on specific API technol-
ogies and concepts. For instance, the RESTful Web Services Cookbook [Allamaraju
2010] explains how to build HTTP resource APIs—for example, which HTTP
method such as POST or PUT to pick. Other books explain how asynchronous mes-
saging works in terms of routing, transformation, and guaranteed delivery [Hohpe
2003]. Strategic DDD [Evans 2003; Vernon 2013] can get you started with API
Preface xxvii

endpoint and service identification. Service-oriented architecture, cloud computing,


and microservice infrastructure patterns have been published. Structuring data stor-
ages (relational, NoSQL) is also documented comprehensively, and an entire pattern
language for distributed systems design is available as well [Buschmann 2007].
Finally, Release It! extensively covers design for operations and deployment to pro-
duction [Nygard 2018a].
The API design process, including goal-driven endpoint identification and opera-
tion design, is also covered well in existing books. For instance, Principles of Web
API Design: Delivering Value with APIs and Microservices [Higginbotham 2021]
suggests four process phases with seven steps. The Design of Web APIs [Lauret 2019]
proposes an API goal canvas, and Design and Build Great Web APIs: Robust, Relia-
ble, and Resilient [Amundsen 2020] works with API stories.
Despite these invaluable sources of design advice, the remote API design space
still is not covered sufficiently. Specifically, what about the structures of the request
and response messages going back and forth between API client and provider? Enter-
prise Integration Patterns [Hohpe 2003] features three patterns representing message
types (event, command, and document message) but does not provide further details
on their inner workings. However, “data on the outside,” exchanged between sys-
tems, differs from “data on the inside” that is processed program-internally [Helland
2005]. There are significant differences between the two types of data in terms of
their mutability, lifetime, accuracy, consistency, and protection needs. For instance,
increasing a local stock-item counter internal to an inventory system probably
requires somewhat less architecture design than product pricing and shipment infor-
mation that is exchanged between manufacturers and logistics companies jointly
managing a supply chain via remote APIs and messaging channels.
Message representation design—data on the outside [Helland 2005] or the “Pub-
lished Language” pattern [Evans 2003] of an API—is the main focus area of this
book. It closes the knowledge gaps regarding API endpoint, operation, and message
design.

Patterns as Knowledge Sharing Vehicles


Software patterns are sophisticated knowledge-sharing instruments with a track
record of more than 25 years. We decided for the pattern format to share API design
advice because pattern names aim at forming a domain vocabulary, a “Ubiquitous
Language” [Evans 2003]. For instance, the enterprise integration patterns have
become the lingua franca of queue-based messaging; these patterns were even imple-
mented in messaging frameworks and tools.
xxviii Preface

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.”

Microservice API Patterns


Our pattern language, called Microservice API Patterns (MAP), provides compre-
hensive views on API design and evolution from the perspective of the messages
exchanged when APIs are exposed and consumed. These messages and their pay-
loads are structured as representation elements. The representation elements differ
in their structure and meaning because API endpoints and their operations have dif-
ferent architectural responsibilities. The message structures strongly influence the
design time and runtime qualities of an API and its underlying implementations; for
instance, few large messages cause network and endpoint workloads (such as CPU
consumption and network bandwidth usage) that differ from those caused by many
small messages. Finally, successful APIs evolve over time; the changes over time have
to be managed.
We chose the metaphor and acronym MAP because maps provide orientation and
guidance, just as pattern languages do; they educate their readers on the options
available in an abstract solution space. APIs themselves also have a mapping nature,
as they route incoming requests to the underlying service implementations.
Preface xxix

We admit that “Microservice API Patterns” might come across as click-bait. In


case microservices are no longer fashionable shortly after this book is published, we
reserve the right to rename the language and repurpose the acronym. For instance,
“Message API Patterns” outlines the scope of the language well too. In the book, we
refer to MAP as “the pattern language” or “our patterns” most of the time.

Scope of the Patterns in This Book


This book is the final outcome of a volunteer project focused on the design and evo-
lution of Web APIs and other remote APIs addressing endpoint and message respon-
sibility, structure, and quality concerns as well as service API evolution. The project
started in the fall of 2016. The resulting pattern language, presented in this book,
helps answer the following questions:

• 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?

We collected our patterns by studying numerous Web APIs and API-related


specifications and reflecting on our own professional experience (before writing any
pattern). We observed many occurrences of the patterns—known uses—both in
public Web APIs and in application development and software integration projects
in industry. Intermediate versions of many of our patterns went through the shep-
herding and writers’ workshop processes at EuroPLoP1 from 2017 to 2020; they were
later published in the respective conference proceedings.2

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

Entry Points, Reading Order, and Content Organization


When maneuvering a complex design space to solve wicked problems [Wikipedia
2022a] (and API design certainly qualifies as sometimes wicked), it is often hard to see
the forest for the trees. It is neither possible nor desirable to serialize or standardize the
problem-solving activities. Therefore, our pattern language has multiple entry points.
Each book part can serve as a starting point, and Appendix A suggests even more.
The book has three parts: Part 1, “Foundations and Narratives,” Part 2, “The
Patterns,” and Part 3, “Our Patterns in Action (Now and Then).” Figure P.1
shows these parts with their chapters and logical dependencies.

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)

Figure P.1 Book parts and their dependencies

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

Figure P.2 Über-pattern map: Chapter flows in Part 2 of the book

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

Appendix A, “Endpoint Identification and Pattern Selection Guides,” provides


a problem-oriented cheat sheet as another option to get started. It also discusses how
our patterns relate to RDD, DDD, and ADDR. Appendix B, “Implementation of the
Lakeside Mutual Case,” shares more API design artifacts from the book’s case study.
Appendix C, “Microservice Domain-Specific Language (MDSL),” provides a
working knowledge of MDSL, a language for microservices contracts with built-in
pattern support via decorators such as <<Pagination>>. MDSL provides bindings
and generator support for OpenAPI, gRPC protocol buffers, GraphQL, and other
interface description and service programming languages.
You will see some (but not much) Java and quite a bit of JSON and HTTP (for
instance, in the form of curl commands and responses to them) as you find your way
through the book. Very little, if any, gRPC, GraphQL, and SOAP/WSDL might also
come your way; if so, it is designed to be simple enough to be understandable without
expertise in any of these technologies. Some of our examples are described in MDSL
(if you are wondering why we created yet another interface description language:
OpenAPI in its YAML or JSON renderings simply does not fit on a single book page
when going beyond HelloWorld–ish examples!).
Supplemental information is available through the Web site companion to this
book:
https://api-patterns.org
We hope you find the results of our efforts useful so that our patterns have a chance
to find their way into the body of knowledge of the global community of integration
architects and API developers. We will be glad to hear about your feedback and con-
structive criticism.

Olaf, Mirko, Daniel, Uwe, Cesare


June 30, 2022

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

Olaf Zimmermann is a long-time service orienteer with a PhD in architectural deci-


sion modeling. As consultant and professor of software architecture at the Institute
for Software at Eastern Switzerland University of Applied Sciences, he focuses on
agile architecting, application integration, cloud-nativity, domain-driven design, and
service-oriented systems. In his previous life as a software architect at ABB and IBM,
he had e-business and enterprise application development clients around the world
and worked on systems and network management middleware earlier. Olaf is a Dis-
tinguished (Chief/Lead) IT Architect at The Open Group and co-edits the Insights
column in IEEE Software. He is an author of Perspectives on Web Services and the
first IBM Redbook on Eclipse. He blogs at ozimmer.ch and medium.com/olzzio.

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.

Daniel Lübke is an independent coding and consulting software architect with a


focus on business process automation and digitization projects. His interests are
software architecture, business process design, and system integration, which inher-
ently require APIs to develop solutions. He received his PhD at the Leibniz Univer-
sität Hannover, Germany, in 2007 and has worked in many industry projects in
different domains since then. Daniel is author and editor of several books, articles,
and research papers; gives training; and regularly presents at conferences on topics of
APIs and software architecture.

Uwe Zdun is a full professor of software architecture at the Faculty of Computer


Science, University of Vienna. His work focuses on software design and architecture,
empirical software engineering, distributed systems engineering (microservices, ser-
vice-based, cloud, APIs, and blockchain-based systems), DevOps and continuous
delivery, software patterns, software modeling, and model-driven development.
Uwe has worked on many research and industry projects in these fields, and in

xxxv
xxxvi About the Authors

addition to his scientific writing is co-author of the professional books Remoting


Patterns—Foundations of Enterprise, Internet, and Realtime Distributed Object
Middleware, Process-Driven SOA—Proven Patterns for Business-IT Alignment, and
Software-Architektur.

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

Foundations and Narratives

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.

From Local Interfaces to Remote APIs


Hardly any fully disconnected application exists today; even standalone applications
typically offer some kind of external interface. A simple example is file export and
import, often text based; even copy-paste capabilities leveraging the operating sys-
tem clipboard can be seen as interfaces. Looking inside applications, every software
component provides an interface as well [Szyperski 2002]. These interfaces describe
which operations, properties, and events a component exposes, but they do not
unveil component-internal data structures or implementation logic. To use a compo-
nent, developers have to learn and understand the interface that it provides. A
selected component might consume the services of other components; in such cases,
it has an outbound dependency on one or more required interfaces.
Some interfaces are more exposed than others. For instance, middleware plat-
forms and frameworks typically provide APIs. APIs with a platform character origi-
nally appeared in operating systems to separate the user application software from
the operating system implementation; POSIX and the Win32 API are two examples
of such platform APIs. These APIs have to be sufficiently general and expressive
for developers to build different kinds of applications; they also should be stable
over multiple operating system releases so that old applications continue working

3
4 Chapter 1 Application Programming Interface (API) Fundamentals

unchanged after operating system upgrades. Promoting the internal interface of


an operating system component to become part of a published API imposes strong
requirements on the quality of its documentation and tight constraints on the kind
of changes it may undergo over time.
APIs not only can cross the boundaries of operating system processes but also can
be exposed on the network. This allows applications running on different physical
or virtual hardware nodes to communicate with each other. Enterprises have been
using such remote APIs to integrate their applications for a long time [Hohpe 2003].
Nowadays, such APIs are commonly found at the boundary between the frontends
of mobile apps or Web applications and the server-side backends of these applica-
tions, often deployed in cloud data centers.
Application frontends often work with shared data managed by their backends.
Hence, the same API may support different kinds of API clients (for example, mobile
apps and rich desktop clients) as well as multiple client instances running concur-
rently. Some APIs even open systems to external clients developed and operated by
other organizations. This openness raises security concerns, for instance, regarding
the application clients or end users that are allowed to access the API. It also has stra-
tegic implications. For example, data ownership and service levels have to be agreed
upon.
Both local component interfaces and remote APIs connecting applications assume
shared knowledge. Two or more parties require this knowledge to write interoper-
able software. Just like it is possible to plug cables into matching electrical sockets
seamlessly, APIs are meant to enable the integration of compatible systems. The
shared knowledge covers:

• Exposed operations and the computation or data manipulation services they


provide.
• Representation and meaning of data exchanged when operations are invoked.
• Observable properties such as information about component state and valid
state transitions.
• Handling of event notifications and error conditions such as component
failure.

Remote APIs also have to define:

• Communication protocols to transfer messages across networks.


• Network endpoints, including location and other access information
(addresses, security credentials).
From Local Interfaces to Remote APIs 5

• Policies regarding failures specific to distribution, including those caused by


the underlying communication infrastructure (examples: timeouts, transport
errors, network and server outages).

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.

A Bit of Distribution and Remoting History


Remote APIs come in many different forms. Over the last 50 years, many concepts
and technologies to decompose applications into distributed systems appeared to let
system parts communicate with each other:

• 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).

While TCP/IP, HTTP, and asynchronous queue-based messaging are as impor-


tant and common as ever today, distributed objects went out of fashion again; some
legacy systems still use them. File transfer via protocols or shared drives is very com-
mon still. Time will tell whether the currently available options are here to stay; new
ones are likely to appear.
All remoting and integration technologies share a common goal—connecting
distributed applications (or their parts) so that they can trigger remote processing
or retrieve and manipulate remote data. Without APIs and API descriptions, these
applications would not know how to connect and talk to remote partner systems or
how to receive and process the replies from these systems.

Remote API: Access to Services via Protocol for Integration


We introduce the API terminology used throughout the book under “A Domain
Model for Remote APIs” later in this chapter. But let us generalize the preceding
observations into a single definition now.
API stands for application programming interface due to the roots of the term
in program-internal decomposition (via local APIs). APIs have a dual nature—they
connect and separate at the same time. In our remoting context, API could therefore
just as well mean access to server-side resources such as data or software services via
a communication protocol for application integration.
Figure 1.1 illustrates the remote messaging concepts that came our way so far.
From Local Interfaces to Remote APIs 7

Application A Application B
API Client API Endpoint Provider
Remote API

Request Response Virtual Service Access Request Response

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.

Real-World APIs from A to Z


APIs today deal with advertising, banking, cloud computing, directories, entertain-
ment, finance, government, health, insurance, jobs, logistics, messaging, news, open
data, payments, QR codes, real estate, social media, travel, URL shortening, visuali-
zation, weather forecasting, and zip codes. On the Web, there are thousands of APIs
providing access to reusable components delivered as a service. Following are exam-
ples from the previous domains:

• 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

• Retrieve information on forex (foreign exchange market), stocks, and com-


modities. Access real-time prices from the markets.
• Access public datasets such as air quality surveillance, parking facilities, elec-
tric and water consumption, COVID cases daily counts, and emergency ser-
vice requests.
• Enable health and fitness data sharing while keeping the user’s privacy and
control.
• Return quotes to travel, home, and car insurance policies. Deliver instant insur-
ance cover to customers.
• Integrate a job database with your software or Web site using methods for
basic job searching, retrieving data for a specific job, and applying to a job.
• Aggregate information from multiple freight carriers, with freight class rating,
shipping cost quotes, and shipment booking and tracking functions with the
ability to arrange for pickup and delivery.
• Send text messages worldwide.
• Harness published content, including news, video, pictures, and multimedia
articles.
• Access online payment solutions featuring invoice management, transaction
processing, and account management.
• Provide access to home valuation services, property details (including histori-
cal sales prices, city and neighborhood market statistics), mortgage rates, and
monthly payment estimates.
• Explore how claims spread across social media. A claim may be a fake news
article, hoax, rumor, conspiracy theory, satire, or even an accurate report.
• Get webcams by categories, country, region, or just nearby your location. Get
timelapse slideshows for every webcam. Add your own webcam.
• Provide programmatic access to current observations, forecasts, weather
watches/warnings, and tropical cyclone advisories using the Digital Weather
Markup Language (DWML).

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

Mobile Apps and Cloud-Native Applications Consume and Provide


Many APIs
The way software is built and made available to end users has changed dramatically
since smartphones such as the iPhone and public clouds such as Amazon Web Ser-
vices (AWS) appeared about 15 years ago. The availability of JavaScript in Web
browsers and the XMLHttpRequest specification2 also played their role in the para-
digm shift toward rich clients such as single-page applications and smartphone apps.
The backends of applications serving mobile apps or other end-user frontend
often are deployed to public or private clouds nowadays. Countless cloud services in
different as-a-service (XaaS) models exist today that can be deployed, rented, scaled,
and billed independently. This massive modularization and (possibly) regional distri-
bution require APIs, both cloud-internal ones and APIs consumed by cloud tenants.
As of 2021, AWS comprises more than 200 services, closely followed by Microsoft
Azure and the Google Cloud.3
When cloud providers offer APIs to their tenants, applications deployed to clouds
start to depend on these cloud APIs but also expose and consume application-level
APIs themselves. Such application-level APIs may connect cloud-external applica-
tion frontends to cloud-hosted application backends; they also may componentize
the application backends so that these backends can benefit from cloud properties
such as pay-per-use and elastic scaling and become true cloud-native applications
(CNAs). Figure 1.2 illustrates a typical CNA architecture.
From an architectural point of view, Isolated State, Distribution, Elasticity, Auto-
mation, and Loose Coupling (IDEAL) are desired properties of CNAs [Fehling 2014].
IDEAL is one of several sets of principles in the literature that characterize cloud
applications. As a superset of IDEAL, the following seven traits summarize what
enables CNAs to operate successfully and to exploit the benefits of cloud computing
[Zimmermann 2021a]:

1. Fit for purpose


2. Rightsized and modular
3. Sovereign and tolerant
4. Resilient and protected

2. Known as AJAX, short for Asynchronous JavaScript and XML: https://developer.mozilla.org/en-US/


docs/Web/Guide/AJAX. Note that JSON is preferred over XML these days, and the Fetch API is more
powerful and flexible than the XMLHttpRequest object.
3. The exact numbers are difficult to pin down and depend on how services are distinguished from one
another.
From Local Interfaces to Remote APIs 11

5. Controllable and adaptable


6. Workload-aware and resource-efficient
7. Agile and tool-supported

Application Application
Frontend Backend

End Users Presentation


Web Application
Logic
Web
APIs

Queue
Tenant Ops Mobile App
APIs Cloud
Database
Business Logic

API
Other Cloud
Storage
Cloud
Compute
API Services

External Services
(Other Cloud, On Premise)

Figure 1.2 Cloud-native application architecture

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.

Microservices Communicate via APIs


It has been hard to escape the term microservices in recent years. Much has been said
about this rather advanced approach to system decomposition since James Lewis
and Martin Fowler’s early online article in April 2014 [Lewis 2014]. They emerged as
service-oriented architectures (SOAs) entered the age of continuous software deliv-
ery and cloud computing. Beyond the hype, microservices are positioned as a sub-
style or implementation approach to SOA, emphasizing independent deployability,
scalability, and changeability of services—as well as themes such as decentralized,
autonomous decision making and container orchestration [Pautasso 2017a].
Each microservice has a single responsibility; this responsibility should represent
a domain-specific business capability. Microservices are often deployed in light-
weight virtualization containers (such as Kubernetes and Docker), encapsulate their
own state, and communicate via remote APIs (often using HTTP but also other pro-
tocols). These service APIs help to ensure a loose coupling with each other and there-
fore their ability to evolve or be replaced without affecting the rest of the architecture
[Zimmermann 2017].
Microservices facilitate software reuse thanks to their limited scope focusing on
the implementation of individual business capabilities. They support agile software
development practices with continuous delivery. For example, each microservice
is typically owned by a single team, allowing this team to independently develop,
deploy, and operate its microservices. Microservices are also well suited for imple-
menting IDEAL CNAs (discussed earlier). When deployed independently, horizontal
on-demand scalability can be achieved through container virtualization and elastic
load balancing. By keeping an existing service API unchanged, they allow an incre-
mental migration of monolithic applications, which reduces the risk of failure of
software modernization efforts.
Microservices also bring new challenges. Their distributed, loosely coupled
nature requires carefully designed APIs and comprehensive systems management.
The communication overhead within a distributed architecture combined with
poor API design choices can impact the performance of microservice architectures.
From Local Interfaces to Remote APIs 13

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.

APIs Are Products and May Form Ecosystems


A software product is a physical or virtual asset that can be purchased (or licensed).
Paying customers have certain expectations regarding longevity, quality, and usabil-
ity of their acquisitions. We already saw examples of APIs that are products in their
own right; others come with software products (for instance, to load these products
with master data or configure and tailor them for a particular user group). Even APIs
that do not have their own business model or any ambitions to contribute to a busi-
ness strategy directly should be “treated as products” [Thoughtworks 2017]. They
are supposed to have a dedicated businessowner, a governance structure, a support
system, and a roadmap.
As an example, a data lake powered by deep-learning algorithms requires data,
which has to come from somewhere. If data is the new oil in the digital era, mes-
sage channels and event streams form the pipelines, with middleware/tools/appli-
cations being the refineries. APIs then are valves located between the pipelines,
producers, and consumers in this metaphor. The data lake can be a marketed prod-
uct exposing APIs but also a company-internal asset that is managed just like a
marketed product.
A software ecosystem “is the interaction of a set of actors on top of a common
technological platform that results in a number of software solutions or services.”
[Manikas 2013]. They consist of organically growing, independent yet related
parts and players. They either are fully decentralized or center on a market maker.
14 Chapter 1 Application Programming Interface (API) Fundamentals

Open-source marketplaces such as the Cloud Foundry Ecosystem qualify as software


ecosystems; another form are resale software ecosystems such as the App Store from
Apple. APIs play a key role to success for both types, allowing applications to join
or leave the ecosystem, to let members communicate and collaborate, to analyze the
health of the ecosystem, and so forth [Evans 2016].
Let’s take a travel management ecosystem as an example. One API is required for
onboarding (loading an ecosystem member such as a tenant of rooms or a transpor-
tation provider, that is). Another one might support the development of travel plan-
ning, reporting, and analysis apps (featuring destination rankings, accommodation
reviews, and so on). These ecosystem parts communicate via APIs—with each other
but also with the market/ecosystem maker when train trips and flights are booked or
hotel rooms are reserved.
Ecosystem success depends on getting the API design and evolution right. The
more complex and dynamic a software ecosystem is, the more challenging becomes
the design of its APIs. Multiple messages travel between the actors, whose relation-
ships are described in the API contracts; the messages form longer-running con-
versations. The members of the ecosystem have to agree on formats, protocols,
conversation patterns, and so forth.

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

Decision Drivers in API Design


The rather unique connect-and-separate role of APIs in an architecture such as that
shown in Figure 1.1 leads to many challenging, sometimes conflicting design con-
cerns. For instance, a balance has to be found between exposing data (so that clients
can make good use of it) and hiding their implementation details (so that they can be
changed as the API evolves). The data representations exposed by APIs not only must
meet the information and processing needs of their clients but also be designed and

4. Bingo!
Decision Drivers in API Design 15

documented in an understandable, maintainable way. Backward compatibility and


interoperability are important qualities.
In this section, we introduce particularly important drivers that we will keep com-
ing back to throughout the book. Let’s start with critical success factors.

What Makes an API Successful?


Success is a relative and somewhat subjective measure. One position on API success
might be
Only an API designed and launched years ago, daily serving requests of billions of pay-
ing clients with minimal latency and zero downtime, qualifies as a successful one.

An opposing position could be


A newly launched API, finally receiving and responding to the first request of an exter-
nal client built entirely on the basis of its documentation with no help or interaction
from the original implementation team, can be considered a success already.

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.

How Do API Designs Differ?


The design of APIs impacts all of software design and architecture. Under “From
Local Interfaces to Remote APIs,” we discussed that APIs rely on assumptions that
independently developed and operated clients and service providers make about each
other. Their success requires the involved parties to reach agreements and keep up
with their end of the bargain for a long time. These assumptions and agreements
concern issues and trade-offs such as the following:

• One general versus many specific/specialized endpoints: Should all clients


use the same interface, or should some or all of them be provided with their
own API? Which of these options makes the API easier to use—for instance, is
a general-purpose API more reusable but also more difficult to apply in specific
cases?
• Fine- versus coarse-grained endpoint and operation scope: How is balance
found between breadth and depth of API functionality? Should the API match,
aggregate, or split the underlying system functionality?
• Few operations carrying much data back and forth versus many chatty
interactions carrying little data: Should request and response messages be
elaborate or narrowly focused in their data content? Which of these two alter-
natives leads to better understandability, performance, scalability, bandwidth
consumption, and evolvability?
Decision Drivers in API Design 17

• Data currentness versus correctness: Is it better to share stale data than to


share none at all? How should natural conflicts between reliable data consist-
ency (within the API provider) and fast response times (as perceived by the API
client) be resolved? Should state changes be reported via polling or pushed by
event notifications or streaming? Should commands and queries be separated?
• Stable contracts versus fast changing ones: How are APIs kept compatible
without sacrificing their extensibility? How are backward-compatible changes
introduced in rich, long-lived APIs?

These questions, options, and criteria challenge API designers; different choices
are made in different requirements contexts. Our patterns discuss possible answers
and their consequences.

What Makes API Design Challenging?


Just as the design of an end-user interface will result in a pleasant or cumbersome
human user experience, an API design will affect the developer experience (DX)—
first and foremost, of client-side developers learning how to use the API to build dis-
tributed applications, but also of developers working on the provider-side API
implementation. Once the API is initially released and runs in production, its design
has a major impact on the performance, scalability, reliability, security, and manage-
ability of the resulting integrated system. Conflicting stakeholder concerns must be
balanced; DX extends into operator and maintainer experience.
The goals and requirements of API providers and clients may overlap but also
conflict; a win-win model is not always achievable. Here are some nontechnical rea-
sons why API design can be hard:

• 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

• Distribution fallacies: Remote APIs are accessed through sometimes unreli-


able networks. What can go wrong will eventually go wrong. For example,
even if a service is up and running, clients may be temporarily unable to reach
it. This makes it particularly challenging to deliver access to an API with high
quality-of-service (QoS) guarantees, for instance, concerning API availability
and response times.
• Illusion of control: Any data exposed in an API can be used by the clients,
sometimes in unexpected ways. Publishing an API means giving up some con-
trol and thus opening up a system to the pressure of external and sometimes
unknown clients. The decision as to which internal system parts and data
sources should become accessible via the API must be made carefully. Once
lost, control is hard if not impossible to regain.
• Evolution pitfalls: While microservices are meant to enable frequent changes,
for instance, in the context of DevOps practices such as continuous delivery,
there is only one chance to get the design of an API right in the first place.
When an API has been released and is successful with more and more clients
depending on it, it will become increasingly expensive to apply corrections
and improvements and impossible to remove features without breaking some
clients. Still, APIs do evolve over time. Changing them requires resolving the
tension between the need for design stability and the need for flexibility by
adopting adequate versioning practices. Sometimes, the provider has enough
market power to dictate the evolution strategies and rhythm; sometimes, the
client community is the stronger end of the API usage relation.
• Design mismatches: What backend systems can do (in terms of functional
scope and quality) and how they are structured (in terms of endpoint and data
definitions) might be different from what clients expect. These differences have
to be overcome by introducing some form of adapters that translate between
mismatching parts. Sometimes, the backend systems have to be refactored or
reengineered to be able to meet external client needs.
• Technology shifts and drifts: User interface technology keeps advancing, for
example, from keyboard and mouse to touchscreen to voice recognition to
motion sensors in virtual and augmented reality (and onward). These advances
require rethinking how users interact with applications. API technology keeps
changing as well—new data representation formats, improved communication
protocols, and changes in the middleware and tools landscape all require con-
tinuously investing in keeping integration logic and communication infrastruc-
ture up to date.5

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.

Architecturally Significant Requirements


Quality goals for APIs come in three forms: developmental, operational, and mana-
gerial. An initial collection follows; more details on these goals are covered in later
chapters.

• Understandability: One important developmental concern in API design is the


structure of the representation elements in request and response messages. To
ensure understandability and avoid unnecessary complexity, it is often advis-
able to follow the domain model closely both in the API implementation code
and in the API. Note that “following” does not imply full exposure or exact
copies here; hiding as much information as possible is in order.
• Information sharing versus hiding: APIs specify what clients can expect
while abstracting how such expectations are met by the provider. It takes
effort to separate the specification from the realization of a software com-
ponent. While a quick solution to design the API may be to simply expose
what is already there, such leaks of implementation details into the inter-
face severely constrain how the implementation can change without affecting
clients later on.
• Amount of coupling: Loose coupling is an internal quality of the structural
design of a distributed system and its components; as an architectural prin-
ciple, it can be seen to reside halfway between a requirement (problem) and a
design element (solution). Loose coupling of communication parties has dif-
ferent dimensions: (a) reference autonomy dealing with naming and address-
ing conventions, (b) platform autonomy hiding technology choices, (c) time
autonomy when supporting synchronous or asynchronous communication,
and (d) format autonomy dealing with data contract design [Fehling 2014].
An API call, by definition, couples client and provider; however, the looser the
coupling, the easier it is to evolve client and provider independently of each
other. One reason is that the knowledge that must be shared by provider and
20 Chapter 1 Application Programming Interface (API) Fundamentals

consumer has an impact on changeability; rightsizing the exposed data struc-


tures, for instance, brings a certain amount of format autonomy. Moreover,
two APIs from the same provider should not be coupled unnecessarily, for
example, via hidden dependencies.
• Modifiability: Modifiability is an important sub-concern of supportability
and maintainability. In the context of API design and evolution, it includes
backward compatibility to promote parallel development and deployment
flexibility.
• Performance and scalability: Latency from an API client point of view, influ-
enced by network behavior such as bandwidth and low-level latency, and
endpoint processing effort including marshalling and unmarshalling of the
payload are important operational concerns. Throughput and scalability pri-
marily are API provider concerns, meaning that response times do not degrade
even if provider-side load grows because more clients use an API or because
existing clients cause more load.
• Data parsimony (or Datensparsamkeit): This is an important general design
principle in distributed systems that are performance- and security-critical.
However, this principle is not always applied when iteratively and incremen-
tally defining an API by specifying its request and response messages—it is
typically easier to add things (in this case, information items or attributes of
value objects) than to remove them.6 Hence, the overall cognitive load and pro-
cessing effort keep increasing during API design and evolution.
Once something is added to an API, it is often hard to determine whether it can
be safely removed, as many (maybe even unknown) clients might depend on it.
Consequently, the API contracts exposed by an API might contain many pos-
sibly complex data elements (such as attributes of customer or product master
data); and very likely, this complexity grows as the software evolves. Variability
management and “option control” are required.
• Security and privacy: Security and privacy often are important considerations
when designing an API, including access control as well as confidentiality and
integrity of sensitive information. For instance, an API might require security
and privacy to avoid exposing confidential elements from the backend services.
To support observability and auditability, API traffic and runtime behavior
should be monitored.

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

To satisfy these sometimes conflicting (and ever-changing) requirements, architec-


tural decisions choose between certain known or new options, with the requirements
being among decision drivers (or criteria). Trade-offs exist and/or must be found/
resolved; our patterns pick the requirements up as design forces and discuss trade-off
resolution.

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

DX = function, stability, ease of use, and clarity.

DX pertains to all things developers work with—tools, libraries and frameworks,


documentation, and so on. The function pillar of DX states that the processing and/
or data management features exposed by some software have a high priority simply
because they are the reason that the client developer is interested in the API at hand;
API features should meet goals of clients. Stability refers to satisfying the desired and
agreed-upon runtime qualities such as performance, reliability, and availability. Ease
of use (of software, for developers) can be achieved with documentation (tutorials,
examples, reference material), community knowledge fora, as well as tool features
(and other ways). The clarity pillar is about simplicity but also observability; the
consequences of certain actions such as hitting a button in a tool, invoking a com-
mand-line interface (or command offered by an SDK), or generating code should
always be clear. If things go wrong, client developers want to know why (invalid
input or provider-side problem?) and what they can do about the problem (retry call
later? correct the input?).
In this context, it is good to be reminded that we design APIs not for ourselves
but for our clients and their software. That said, machine-to-machine communica-
tion is fundamentally different from human-computer interaction—simply because
humans and computers work and behave differently. Programs might think (sort of)
but do not feel and have no awareness of themselves and their environment.7 Hence,
some but not all UX advice applies to DX straightaway.

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.

A Domain Model for Remote APIs


This book and its pattern language use a set of basic abstractions and concepts that
form a domain model [Zimmermann 2021b] for API design and development. While
we introduce all building blocks of our patterns in this domain model, we do not aim
at painting a unified picture of all communication concepts and integration architec-
tures that exist. The relation of the domain model elements to concepts in HTTP
and other remoting technologies is explained though.

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

API Client API Provider

* 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

Endpoints Offer Contracts Describing Operations


As shown in Figure 1.4, an API contract describes operations. In addition to the
endpoint address, an operation identifier distinguishes operations. For instance,
the top-level XML tag in the body of a SOAP message has this duty. In RESTful
HTTP, the name of the HTTP method (also called the verb) is unique within a
single resource.9

API Contract Operation Conversation Message


describes invoked in comprises
+ ID:String - header
1 * 1 * * * - body

Figure 1.4 Domain model: Operations, conversations, messages

Messages as Conversation Building Blocks


The operations of an API, described by its contract and offered by its endpoints, can
participate in conversations. Conversations differ in the way they combine and com-
pose messages. Each conversation describes a sequence of messages exchanged
between the involved communication participants. Figure 1.5 shows four main types
of conversations. A request-reply message exchange consists of a single request mes-
sage followed by a single response message. If there is no response, the conversation
has a one-way exchange nature. A third form of conversation is an event notifica-
tion, which features a single message containing the triggered event. Finally, a con-
versation can be long running; an initial single request is then followed by multiple
replies. In this request–multiple replies case, one message, sent from the client to the
provider, registers a callback, and one or more messages, sent from provider to client,
perform the callback action.
Three types of messages are command message, document message, and event
message [Hohpe 2003]. These three types match the conversation types naturally;
document messages, for instance, can be transferred in a one-way exchange; com-
mand messages require request-reply conversations if the client cares about the
command execution outcome. Messages can be delivered in multiple over-the-wire
formats such as JSON or XML. In this book, we are primarily interested in the con-
tent and structure of these messages (of all three types).

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)

Figure 1.5 Domain model: Conversation types and message types

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.

Message Structure and Representation


Figure 1.6 illustrates that one or more representation elements, also known as param-
eters, constitute the representation of a message sent over the wire (note that some
technologies use the term operation signature to refer to parameters and their types).
Messages carry data and metadata, which can be found in the message header and its
body. The representation elements in addresses, headers, and body may or may not
be ordered and further structured into hierarchies; they often are named and can be
typed statically or dynamically. Messages may carry the address they are coming
from (for instance, in order to enable sending a reply back to that address) and/or the
addresses they are sent to. For instance, concepts such as return address and correla-
tion identifier allow the message to participate in content-based message routing and
26 Chapter 1 Application Programming Interface (API) Fundamentals

complex, long-running conversations [Hohpe 2003]. In HTTP resource APIs, hyper-


media controls (links) contain such address information. If addresses do not appear
in a message, the communication channel solely takes care of the message routing.
We also call the message representations data transfer representation (DTR).
Such DTR should not make any assumption about client- and server-side program-
ming paradigms (such as object-oriented, imperative, or functional programming);
the client-server interactions are plain messages (for instance, they do not contain
any remote object stubs or handlers).10 The process of converting a programming
language representation into a DTR that can be sent over the wire is called serializa-
tion (also known as marshalling); the opposite operation is called deserialization (or
unmarshalling). These terms are commonly used in distributed computing technolo-
gies and middleware platforms [Voelter 2004]. Plain text as well as binary formats
are often used to send and receive DTRs; as already mentioned, JSON and XML are
common choices.

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() * *

Figure 1.6 Domain model: Message details

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..*

Operation API Endpoint

+ ID: String

Figure 1.7 Domain model: An API contract describes operations (that are invoked in
conversations comprising messages)

Domain Model Usage throughout the Book


The abstract concepts in the domain model form a vocabulary for the pattern lan-
guage introduced in this book, as the pattern texts have to remain platform- and
technology-independent by definition (except for their illustrative examples). More-
over, each concept and relationship in the domain model can potentially serve as a
28 Chapter 1 Application Programming Interface (API) Fundamentals

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

when end-user interfaces such as browser-based single-page applications as well as


the backend services within distributed cloud applications require remote APIs to
communicate with each other.
During the architectural decision making, a number of quality attributes have
to be taken into account. The developmental qualities for APIs range from a pleas-
ant client-side DX, affordable cost, and sufficient performance to sustainable and
change-friendly operations and maintenance on the provider-side. Across the entire
API life cycle, three types of quality attributes are particularly relevant:

1. Development qualities: APIs should be straightforward to discover, learn, and


understand by developers and easily consumable to build applications. This is
collectively referred to as providing a positive DX, defined via the four pillars
function, stability, ease of use, and clarity.
2. Operational qualities: APIs and their implementations should be dependable
and meet the performance, reliability, and security requirements that have been
stated for them. They should be manageable at runtime.
3. Managerial qualities: APIs should be evolvable and maintainable over time,
preferably being both extensible and backward compatible, so that changes are
possible but do not break existing clients. Agility and stability have to be bal-
anced here.

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

Lakeside Mutual Case Study

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.

Business Context and Requirements


One of the agile development teams in corporate IT of Lakeside Mutual has just
been tasked with extending a customer application with a self-service capability. An
early architectural spike has unveiled that the required customer and policy data are
scattered across several backend systems. None of these systems offer suitable Web
APIs or message channels that provide the required data.
The following analysis and design artifacts have already been created by the devel-
opment team:

31
32 Chapter 2 Lakeside Mutual Case Study

• User stories accompanied by desired system quality attributes and an analysis-


level domain model
• A system context diagram/context map sketching available and required
interfaces
• An architecture overview diagram showing the existing system parts and their
relationships

Let us inspect these artifacts now. They provide valuable input to the API design.

User Stories and Desired Qualities


The next version of the customer application is supposed to support several new self-
service features, one of which has been captured in the following user story:
As a customer of Lakeside Mutual, I want to update my contact information myself
online so that the data is current. I do not want to have to call an agent for that, which
may involve long waiting times.

Requirements regarding desired system qualities (for example, performance,


availability, and maintainability) have been gathered. The user story about contact
information update should not take longer than two seconds in 80 percent of the
executions. Lakeside Mutual expects 10,000 customers to use the new online service,
10 percent of which work with the system concurrently.
Usability is another significant concern. If the new self-service capability does not
help clients achieve their self-service goals effectively, they might revert to more costly
channels, defeating the whole purpose of the new capability. The same, although
to a lesser degree, applies to reliability requirements. The interface should be avail-
able during extended office hours and on weekends and holidays when the clients of
Lakeside Mutual might have time to take care of their insurance contracts.
Given these requirements, any chosen architecture and frameworks should sup-
port the development and operations teams at Lakeside Mutual effectively and effi-
ciently. They should be able to monitor and manage the application and maintain it
over time.

Analysis-Level Domain Model


Customers and their insurance policies constitute the core of the system (master
data management). With the new self-service frontend, customers will not only be
able to update their contact information, but will also be able to request quotations
for different insurance policies, all without having to go to a branch office or
Business Context and Requirements 33

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

inquire about issued by

«Aggregate» «Aggregate»
Policy Customer
insures

Figure 2.1 Aggregate overview

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

«Aggregate Root» «Aggregate»


InsuranceQuoteRequest policy Policy

- id: long
- date: Date

customer
insuranceQuote

«Aggregate»
Customer
«entity» «entity»
InsuranceQuote CustomerInfo

- expirationDate: Date - id: long


- rstName: String - rstName: String
- lastName: String - lastName: String

policyLimit insurancePremium contactAddress billingAddress

«Value Object» «Value Object»


MoneyAmount Address

- amount: BigDecimal - streetAddress: String


- currency: Currency - postalCode: String
- city: String

Figure 2.2 Details of the InsuranceQuoteRequest aggregate

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

«Value Object» «Aggregate Root» «Aggregate»


PolicyId id Policy customer Customer

- creationDate: Date

deductible policyLimit
policyType insurancePremium policyPeriod insuringAgreement

«Value Object» «Value Object» «Value Object» «entity»


PolicyType MoneyAmount PolicyPeriod InsuringAgreement

- name: String - amount: BigDecimal - startDate: Date


- currency: Currency - endDate: Date

agreementItems

«Value Object»
InsuringAgreementItem

Figure 2.3 Details of the Policy aggregate


Architecture Overview 35

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.

«Aggregate Root» «Aggregate»


InsuranceQuoteRequest Policy

customer customer
«Aggregate»
Customer

«Aggregate Root»
Customer

id customerProfile

«Value Object» «entity» currentAddress «Value Object»


CustomerId CustomerProfile Address

- streetAddress: String
- postalCode: String
moveHistory - city: String

Figure 2.4 Details of the Customer aggregate

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

service, which is also used by a Policy Management application and a company-


internal Customer Management application.2

Customer Core
U OHS
U
U
Customer/Supplier

D CF
D

Policy Management Customer Management

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

supporting backend microservices (for instance, Customer Management frontend


and Customer Management backend).

«React : SPA» «React : SPA» «Vue.js : SPA»


Customer Customer Self- Policy
Management Service Frontend Management
Frontend Frontend

HTTP + WebSocket HTTP + HTTP HTTP HTTP


WebSocket

«Spring Boot» «Spring Boot» «Spring Boot»


Customer Customer Self- Policy
ActiveMQ
Management Service Backend Management
Backend Backend

HTTP HTTP HTTP

«Spring Boot»
Customer Core

Figure 2.6 Service components at Lakeside Mutual and their relationships

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.

Lakeside Mutual has decided to realize a microservices architecture. The rationale


for this strategic architectural decision is to upgrade system parts more flexibly (in
response to business change requests) and be prepared for business growth (which
is expected to increase workload, possibly turning the backends into bottlenecks
requiring independent scaling).
Target API Specification 39

API Design Activities


We now turn back to our initial user story of providing a means for insurance cus-
tomers to update their contact information.
The customer self-service team has just taken the above user story off its backlog
and included it in the current sprint. During a sprint planning meeting, the teams
identified the following activities for the next iteration:

1. Design a platform-independent API for the upstream Customer Management


Backend, consumed by the downstream Customer Self-Service Frontend.
2. Specify the API endpoints (resources if we assume an HTTP-based Web API)
and their operations (HTTP verbs/methods such as GET and POST), includ-
ing request parameters and response structure (for example, object structure
of JSON payloads).
3. Justify decisions based on the analysis and design artifacts listed or referenced
earlier in this chapter.

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.

Target API Specification


The following sketch of an API shows what an endpoint to update customer contact
information could look like when performing the required API design activities (note
that this sketch serves as a preview here; there is no need to understand all details
already at this point):

API description CustomerManagementBackend


usage context SOLUTION_INTERNAL_API
for FRONTEND_INTEGRATION

data type CustomerId ID


data type CustomerResponseDto D

data type AddressDto {


"streetAddress": D<string>,
40 Chapter 2 Lakeside Mutual Case Study

"postalCode": D<string>,
"city": D<string>
}

data type CustomerProfileUpdateRequestDto {


"firstname": D<string>,
"lastname": D<string>,
"email": D<string>,
"phoneNumber": D<string>,
"currentAddress": AddressDto
}

endpoint type CustomerInformationHolder


version "0.1.0"
serves as INFORMATION_HOLDER_RESOURCE
exposes
operation updateCustomer
with responsibility STATE_TRANSITION_OPERATION
expecting
headers
<<API_Key>> "accessToken": D<string>
payload {
<<Identifier_Element>> "id": CustomerId,
<<Data_Element>>
"updatedProfile":
CustomerProfileUpdateRequestDto
}
delivering
payload {
<<Data_Element>> "updatedCustomer": CustomerResponseDto,
<<Error_Report>> {
"status":D<string>,
"error":D<string>,
"message":D<string>}
}

The API is specified in the MDSL specification language. MDSL, introduced in


Appendix C, “Microservice Domain-Specific Language (MDSL),” is a domain-specific
language (DSL) to specify (micro-)service contracts, their data representations, and
API endpoints. OpenAPI specifications can be generated from it (the OpenAPI version
of the preceding contract accounts for 111 lines in its YAML4 rendering).

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:

1. Web APIs connect the application frontends with the backends.


2. The backends also communicate via APIs.
3. API design starts with user requirements, desired qualities, system context
information, and architectural decisions made already.

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 Decision Narratives

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.

Prelude: Patterns as Decision Options, Forces as


Decision Criteria
Selecting a pattern is an architectural decision to be made and justified, as motivated,
for instance, in Continuous Architecture in Practice [Erder 2021]. Hence, our narra-
tion identifies the architectural decisions required during API design and evolution.
For each of these decisions, we discuss its decision-making criteria and design

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:

Decision: Example of a decision required


Which topic is addressed?

The eligible patterns are then presented in the following format:

Pattern: PattErn namE


Problem [Which design issue is addressed?]
Solution [Overview of possible ways to address the issue]

The decision-making criteria, corresponding to the pattern forces from Part 2,


are then summarized, and some good practice recommendations are given (which
should not be followed word for word but should be put into the context of a par-
ticular API design effort).

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].

This format, called a why-statement [Zdun 2013], is an example of an architec-


tural decision record template. Popularized by Michael Nygard [Nygard 2011], such
decision logs have a long history in research and practice.1 In a nutshell, they keep
track of decision outcomes and their justifications (rationale) in a given context.
An instance of the ADR template could be written as follows:

In the context of the pattern decision narratives,


facing the need to illustrate the options and criteria in examples,

1. See https://ozimmer.ch/practices/2020/04/27/ArchitectureDecisionMaking.html.
Foundational API Decisions and Patterns 45

we decided to inject architectural decision records like this one


to achieve a balance of theory and practice,
accepting that the chapter gets longer and readers have to jump from concepts to
their application when reading end to end.

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.

Two interludes cover “Responsibility and Structure Patterns in the Lakeside


Mutual Case” and “Quality and Evolution Patterns in the Lakeside Mutual Case.”

Foundational API Decisions and Patterns


In Chapter 1, “Application Programming Interface (API) Fundamentals,” we saw
that APIs are software interfaces that expose computing or information
46 Chapter 3 API Decision Narratives

management services while decoupling the underlying service provider implementa-


tions from API clients. In this section, we introduce foundational architectural design
decisions with patterns as decision options, detailing this relation between service
implementations at the API provider side and the API clients. The patterns in this
section have a managerial or organizational theme and also have a substantial impact
on important technical considerations.
The decisions in this section answer the following questions:

• 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?

Figure 3.1 shows how these decisions are related.

«Category»
Foundations

«Decision»
API Visibility
«Optional Next» «Optional Next»
document visible combine integration type
aspects of the API with selected visibility
contract option

«Decide for some


«Decision» instances of» «Decision»
Documentation «Optional Next» API Integration
of the API Types
codify integration
aspects of the API

«Decide for some «Decide for some


instances of» instances of»
«Basic Concept»
API

Figure 3.1 Foundations category


Foundational API Decisions and Patterns 47

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

The core decision to be taken is as follows:

Decision: Visibility of the API


Where should the API be accessible from: the Web, an access-controlled network
such as an intranet or an extranet, or only the data center that hosts a particular
solution?

Figure 3.2 illustrates the three decision options for this decision, described as
patterns.

«Decision»
API Visibility

«Option» «Option» «Option»


expose the API expose the API expose the API only
publicly over the only to a specific to a group or subgroup
Internet user group within an organization

«Pattern» «Pattern» «Pattern»


Public API Community API Solution-Internal
API

Figure 3.2 API visibility decision

The first option is the Public API pattern.

Pattern: PubLiC aPi


Problem How can an API be made available to an unlimited and/or unknown number
of API clients outside the organization that are globally, nationally, and/or
regionally distributed?
Solution Expose the API on the public Internet along with a detailed API Description that
describes both functional and nonfunctional properties of the API.
Foundational API Decisions and Patterns 49

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.

Pattern: Community aPi


Problem 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 multiple legal
entities (such as companies, nonprofit/nongovernment organizations, and
governments)?
Solution 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.
50 Chapter 3 API Decision Narratives

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.

Pattern: soLution-intErnaL aPi


Problem How can access to and usage of an API be limited to an application, for
instance, components in the same or another logical layer and/or physical tier?
Solution Decompose the application logically into components. Let these components
expose local or remote APIs. Offer these APIs only to system-internal
communication partners such as other services in the application backend.
Foundational API Decisions and Patterns 51

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

accepting that unregistered users (prospective customers) cannot be served by


this API.

API Integration Types


A second foundational decision is which integration types are supported by the API:

Decision: Integration types supported by the API


Do the API clients display forms and processing results to end users, for instance,
in mobile apps, Web applications, and rich client applications? Or should they
serve as wrappers and adapters in mid-tiers and backend tiers that host applica-
tion components?

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

Figure 3.3 API integration types decision

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.

Pattern: frontEnd intEgration


Problem 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 activities in a backend or
upload data to it?
Solution Let the backend of a distributed application expose its services to one or more
application frontends via a message-based remote Frontend Integration API.

How to design a Frontend Integration API strongly depends on the informa-


tion and business needs of the frontends. Especially if the frontend contains a user
interface (UI), rich and expressive APIs might be required to address all the UI’s
needs (for example, the API should support the Pagination pattern to make it effi-
cient for the UI to fetch additional information incrementally). This enables a pleas-
ant API client developer experience. However, more expressive APIs are often costly
to develop and might cause tighter coupling than simpler alternatives. Additional
efforts and tight coupling might translate to higher risks.
For a Frontend Integration API security and data privacy considerations are
usually important, as many application frontends work with sensitive data such as
customer information.

Pattern: baCkEnd intEgration


Problem How can distributed applications and their parts, which have been built
independently and are deployed separately, exchange data and trigger mutual
activity while preserving system-internal conceptual integrity without
introducing undesired coupling?
Solution Integrate the backend of a distributed application with one or more other
backends (of the same or other distributed applications) by exposing its services
via a message-based remote Backend Integration API.
54 Chapter 3 API Decision Narratives

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:

• Public APIs often provide Frontend Integration capabilities to connect


Web applications or mobile frontends. They can also be used to support Back-
end Integrations, for instance, to feed data lakes in big data scenarios with
open data.
• Community APIs often support Backend Integration scenarios, for instance,
data replication or event sourcing. They might also support Frontend Inte-
gration in portals and mashups.
• Finally, Solution-Internal APIs might support Frontend Integration to
support API clients serving end user interfaces only used within the solution.
They also might support Backend Integration in a local context, such as
local extract, transform, and load (ETL) processes.

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.

Documentation of the API


In addition to the foundational decisions on API visibility and API integration types,
it should be decided if and how the API should be documented. This decision is illus-
trated in Figure 3.4.

«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

«Can Include» «Has Variant»


a formal technical part API-specific variant of the general
describing the API interface description pattern in
distributed systems
«Domain Class»
API Contract

Figure 3.4 API documentation decision

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

Pattern: aPi dEsCriPtion


Problem Which knowledge should be shared between an API provider and its clients? How
should this knowledge be documented?
Solution Create an API Description that defines request and response message structures,
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.

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.

Sample decision outcome. Lakeside Mutual decided to apply the pattern:


In the context of the customer self-service channel,
wanting to improve the client developer experience,
the Lakeside Mutual API designers chose elaborate API Descriptions and the
contract languages MDSL and OpenAPI,
to achieve an interoperable API that is easy to learn and use,
accepting that its documentation has to be kept current as the API evolves.

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.”

Decisions about API Roles and Responsibilities


Two questions arise when designing API endpoints and their operations:

• Which architectural role should an API endpoint play?


• What is the responsibility of each API operation?

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

«Decide for some «Decide for some


instances of» instances of»

«Domain Class» «Domain Class»


API Endpoint Operation

Figure 3.5 Responsibility category


Decisions about API Roles and Responsibilities 59

Architectural Role of an Endpoint


The API requirement analysis might lead to a list of candidate API endpoints, for
instance, HTTP resources. At the beginning of a project or product development,
these interfaces are yet unspecified (or only partially specified). API designers have to
address semantic concerns and find an appropriate business granularity for the ser-
vices exposed by the API. Simplistic statements such as “services in a service-oriented
architecture (SOA) are coarse-grained by definition, while microservices are fine-
grained; you cannot have both in one system” or “always prefer fine-grained over
coarse-grained services” are insufficient because project requirements and stakeholder
concerns differ [Pautasso 2017a]. Context always matters [Torres 2015]; cohesion and
coupling criteria come in many forms [Gysel 2016]. As a result, the nonfunctional
requirements for service design often are conflicting [Zimmermann 2004].
In response to these general challenges, a major decision for the endpoints of an
API is to decide which architectural role they should play. This, in turn, can help to
improve the selection and decomposition of the (candidate) API endpoints.

Decision: Architectural role of an endpoint


Which technical role should an API endpoint play in the architecture?

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

Figure 3.6 Responsibility category: Architectural role of an endpoint


60 Chapter 3 API Decision Narratives

Processing Resources are resources whose primary function is to handle incom-


ing action requests (aka commands or activities).

Pattern: ProCEssing rEsourCE


Problem How can an API provider allow its clients to trigger an action in it?
Solution Add a Processing Resource endpoint to the API exposing operations that bundle
and wrap application-level activities or commands.

In contrast, Information Holder Resources are resources whose primary


function is to expose storage and management of data or metadata, including its
creation, manipulation, and retrieval.

Pattern: information HoLdEr rEsourCE


Problem How can domain data be exposed in an API, but its implementation still be
hidden? How can an API expose data entities so that API clients can access and/
or modify these entities concurrently without compromising data integrity and
quality?
Solution Add an Information Holder Resource endpoint to the API, representing a
data-oriented entity. Expose create, read, update, delete, and search operations in
this endpoint to access and manipulate this entity.
In the API implementation, coordinate calls to these operations to protect the data
entity.

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.

Refining Information Holder Roles


Information Holder Resources have the primary function to expose storage and
management of data or metadata, including its creation and retrieval. There are sev-
eral patterns covering types of information holders, refining the general Informa-
tion Holder Resource pattern. Figure 3.7 provides an overview.
62 Chapter 3 API Decision Narratives

resource whose primary function


is supporting clients that follow or
«Pattern» «Pattern» de-reference links to other «Pattern»
resource that stores short-
Operational living, operational data Information resources Link Lookup
Data Holder Holder Resource Resource

resource that stores long-living resource whose primary function is to


and frequently referenced, but offer a shared data exchange between
still mutable data other resources
resource that stores long-living
data that cannot be altered by
clients

«Pattern» «Pattern» «Pattern»


Master Data Reference Data Data Transfer
Holder Holder Resource

Figure 3.7 Responsibility category: INFORMATION RESOURCE HOLDER types

In the context of these information holder roles, we distinguish three types of


data, which are the basis for defining the roles described in the first three patterns:

• Operational data covers the events in the transactions of an organization.


For example, making an order to a business, shipping items to a customer, or
hiring employees are all examples of business transactions that would form
operational data. Operational data (also called transactional data) is usually
short-living, transactional in nature, and has many outgoing relationships.
• Master data is essential information that supports the business transactions
realized in a system. Typically, it covers the digital representation of the par-
ties of an organization such as persons, customers, employees, or suppliers. It
also covers the main things relevant to an organization, such as the products,
materials, items, and vehicles. Finally, master data may represent physical or
virtual places, such as locations or sites. Master data is usually long-living and
frequently referenced.
• Reference data is inert data referenced and shared in one or more systems
and among the microservices and components making up these systems.
Examples are country codes, zip codes, and delivery status codes (such as
pending, information received, in transit, out on delivery, failed attempt,
delivered). Reference data is long-living, simple, and cannot be changed by
clients directly.
Decisions about API Roles and Responsibilities 63

The Information Holder Resource role supporting operational data is Oper-


ational Data Holder. An important decision driver for this option usually is a
high processing speed of the update operations. Services dealing with operational
data must also be easy to change to support business agility and update flexibility.
Nonetheless, the created and modified operational data must meet high accuracy
and quality standards in many (business) scenarios. For example, qualities such as
conceptual integrity and consistency must be supported.

Pattern: oPErationaL data HoLdEr


Problem How can an API support clients that want to create, read, update, and/or delete
instances of domain entities that represent operational data: data that is rather
short-lived, changes often during daily business operations, and has many
outgoing relations?
Solution Tag an Information Holder Resource as Operational Data Holder and add
API operations to it that allow API clients to create, read, update, and delete its
data often and fast.

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.

Pattern: mastEr data HoLdEr


Problem 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?
Solution Mark an Information Holder Resource to be a dedicated Master Data
Holder endpoint that bundles master data access and manipulation operations
in such a way that the data consistency is preserved and references are managed
adequately. Treat delete operations as special forms of updates.
64 Chapter 3 API Decision Narratives

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.

Pattern: rEfErEnCE data HoLdEr


Problem 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?
Solution Provide a special type of Information Holder Resource endpoint, a
Reference Data Holder, as a single point of reference for the static, immutable
data. Provide read operations, but no create, update, or delete operations in this
endpoint.

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).

Pattern: Link LookuP rEsourCE


Problem How can message representations refer to other, possibly many and frequently
changing, API endpoints and operations without binding the message recipient to
the actual addresses of these endpoints?
Solution Introduce a special type of Information Holder Resource, a dedicated Link
Lookup Resource endpoint that exposes special Retrieval Operation operations
that return single instances or collections of Link Elements that represent the
current addresses of the referenced API endpoints.

A Data Transfer Resource is an endpoint role pattern representing a resource


whose primary function is to offer a shared data exchange between clients. This
might help to reduce coupling between the communication participants interacting
with the Data Transfer Resource; in terms of time—the API clients do not have
to be up and running at the same time—and location—the API clients do not have
to know the addresses of each other as long as they can locate the Data Transfer
Resource. The pattern can help overcome certain communication constraints, such
as if one party cannot be directly connected to another one. An asynchronous, per-
sistent Data Transfer Resource is more reliable than, for example, client/server
communication. It can also offer good scalability, but measures must be taken to deal
with a possibly unknown number of recipients that can impede scalability. Indirect
communication can introduce additional latency though. The data to be exchanged
has to be stored somewhere, and sufficient storage space must be available. Finally,
66 Chapter 3 API Decision Narratives

ownership of the shared information has to be established to achieve explicit control


over the resource availability life cycle.

Pattern: data transfEr rEsourCE


Problem How can two or more communication participants exchange data without
knowing each other, without being available at the same time, and even if the
data has already been sent before its recipients became known?
Solution Introduce a Data Transfer Resource as a shared storage endpoint accessible
from two or more API clients. Provide this specialized Information Holder
Resource with a globally unique network address so that two or more clients
can use it as a shared data exchange space. Add at least one State Creation
Operation and one Retrieval Operation to it so that data can be placed in the
shared space and also fetched from it.

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.

Defining Operation Responsibilities


Once an endpoint role is decided, more fine-grained decisions have to be made for its
operations, covered in four patterns of widely used API operation responsibilities.
These patterns are solution options in the decision illustrated in Figure 3.8.

Decision: Operation responsibility


What are the read-write characteristics of each API operation?
Decisions about API Roles and Responsibilities 67

«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

Figure 3.8 Responsibility category: Operation responsibilities

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’

Pattern: statE CrEation oPEration


Problem How can an API provider allow its clients to report that something has happened
that the provider needs to know about, for instance, to trigger instant or later
processing?
Solution 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.

The next option is a Retrieval Operation, representing a read-only access oper-


ation that only finds and delivers data without allowing clients to change any data.
The data may be manipulated in the Retrieval Operation before sending it to cli-
ents, though, for instance, to optimize the transfer by aggregating data elements.
Some retrieval operations search for data; others access single data elements. Data
properties such as veracity, variety, velocity, and volume should be considered in the
design of the operation, as data comes in many forms and client interest in it varies.
In addition, workload management considerations should be made, especially if sig-
nificant data volumes are transferred. Also, more information transferred from client
to API provider (and back) can lead to higher coupling and larger message sizes.

Pattern: rEtriEVaL oPEration


Problem 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?
Solution 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.

A State Transition Operation is an operation that performs one or more activi-


ties, causing a server-side state change. Examples of such operations are full and par-
tial updates to server-side data as well as deletions of such data. Advancing the state
of long-running business process instances also requires State Transition Opera-
tions. The data to be updated or deleted might have been created via a previous
call of a State Creation Operation or initialized internally by the API provider (in
other words, the creation might not be caused by and not be visible to the API client).
Decisions about API Roles and Responsibilities 69

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’

Pattern: statE transition oPEration


Problem How can a client initiate a processing action that causes the provider-side
application state to change?
Solution Introduce an operation in an API endpoint that combines client input and current
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 Processing
Resource or an Information Holder Resource, and check the validity of
incoming change requests and business activity requests at runtime.

A Computation Function is an operation that computes a result solely from the


client input and does not read or write server-side state. The different performance
and message size considerations elaborated previously are relevant for Computation
Functions as well. In many cases, Computation Functions require reproducibility
of executions. Some computations might require a lot of resources, such as CPU time
and main memory (RAM); for such functions, workload management is essential. As
many Computation Functions change often, maintenance requires special consid-
eration, in the sense that updating the provider side is easier than updating clients.

Pattern: ComPutation funCtion


Problem How can a client invoke side-effect-free remote processing on the provider side
to have a result calculated from its input?
Solution Introduce an API operation cf with cf: in -> out to the API endpoint, which
often is a Processing Resource. Let this Computation Function validate the
received request message, perform the desired function cf, and return its result
in the response.
70 Chapter 3 API Decision Narratives

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of the Customer Core INFORMATION HOLDER RESOURCE,
facing the need to achieve a high level of automation and a wide range of clients,
the API designers at Lakeside Mutual decided to introduce operations realizing
all four responsibility patterns (read, write, read-write, compute)
to achieve both read and write access to the customer master data plus validation
support
accepting that concurrent access must be coordinated, and interactions might
get rather chatty when too fine-grained create, read, update, write operations are
specified.

In Part 2, the patterns covering the architectural roles of an endpoint appear in


Chapter 5, “Define Endpoint Types and Operations.” The operation responsibility
patterns are featured in that chapter as well.

Selecting Message Representation Patterns


In addition to endpoints and operations, API contracts define the structure of the
messages exchanged when invoking the operations. The structural representation
category of our pattern language deals with how to design such message representa-
tion structures. It deals with the following design issues:

• 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.

«Category» «Domain Class»


Structural «Decide for all instances of» Message
Representation

«Decision» «Decision» «Decision»


Exchange of Structure of Meaning of
Context Parameter Stereotypes of
Information Representation Message
Required Elements
«Optional Next»

«Optional Next»
«Decision»
Subset of High
Number and
Data Records
with the Same
Structure
Required

Figure 3.9 Structural representation category

Flat versus Nested Structure of Representation Elements


A major decision in structural representation design is as follows:

Decision: Structure of parameter representation


What is the adequate overall representation structure for the data elements to be
transmitted in the message?
72 Chapter 3 API Decision Narratives

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

Figure 3.10 Structure of parameter representation decision

The simplest decision option is that a scalar representation is sufficient. In that


case, the Atomic Parameter pattern should be chosen.

Pattern: atomiC ParamEtEr


Problem How can simple, unstructured data (such as a number, a string, a Boolean value,
or a block of binary data) be exchanged between API client and API provider?
Solution Define a single parameter or body element. Pick a basic type from the type system
of the chosen message exchange format for it. If justified by receiver-side usage,
identify this Atomic Parameter with a name. Document name (if present), type,
cardinality, and optionality in the API Description.
Selecting Message Representation Patterns 73

Sometimes, multiple scalars need to be transmitted. In such cases, a list repre-


sentation usually is the best decision option, following the Atomic Parameter List
pattern.

Pattern: atomiC ParamEtEr List


Problem How can multiple related Atomic Parameters be combined in a representation
element so that each of them stays simple, but their relatedness becomes explicit
in the API Description and the runtime message exchanges?
Solution Group two or more simple, unstructured data elements in a single cohesive
representation element to define an Atomic Parameter List that contains multiple
Atomic Parameters. Identify its items by position (index) or by a string-valued
key. Identify the Atomic Parameter List as a whole with its own name as well if
that is needed to process it in the receiver. Specify how many elements are required
and permitted to appear.

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.

Pattern: ParamEtEr trEE


Problem How can containment relationships be expressed when defining complex
representation elements and exchanging such related elements at runtime?
Solution Define a Parameter Tree as a hierarchical structure with a dedicated root
node that has one or more child nodes. Each child node may be a single Atomic
Parameter, an Atomic Parameter List, or another Parameter Tree, identified
locally by a name and/or by position. Each node might have an exactly-one
cardinality, but also a zero-or-one cardinality, an at-least-one cardinality, or a zero-
or-more cardinality.

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

Pattern: ParamEtEr forEst


Problem How can multiple Parameter Trees be exposed as request or response payload
of an API operation?
Solution Define a Parameter Forest comprising two or more Parameter Trees. Locate
the forest members by position or name.

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»

«Uses» «Pattern» «Uses»


Atomic
Parameter List

«Can Use»
as wrapper «Uses»
structure for
«Pattern» transport «Pattern»
Parameter Tree Atomic
Parameter
«Uses»

Figure 3.11 Dependencies of patterns for the structure of parameter representation

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

in an enumeration). If the API contract is underspecified, interoperability issues


may arise, for instance, when dealing with optionality (which can be indicated by
absence but also by dedicated null values) and other forms of variability (for exam-
ple, choosing between different representations). If the contract is overspecified, it
becomes inflexible with backward compatibility becoming hard to preserve. Simple
data structures lead to fine-grained service contracts; complex ones are often used
for coarse-grained services (that cover a large amount of business functionality).
In a few cases, interoperability concerns related to standardization might govern
the decisions. If, for instance, a standard exchange format exists, the standard format
might be chosen in order to save design effort even though a customized special-
purpose format could be more understandable and more efficient to transfer.
Developer convenience and experience, including learning and programming
effort, might also influence the decision on the structure of message representations.
These aspects are closely related to understandability, simplicity, and complexity
considerations. For instance, structures that are easy to create and populate might be
difficult to understand or debug, whereas a compact format that is light in transfer
might be difficult to document, understand, and parse.
Security (data integrity and confidentiality in particular) and data privacy concerns
are relevant because security solutions might require additional message payload
such as keys and tokens (often signed and/or encrypted). Another important consid-
eration is which payload should actually be sent and how it should be protected. A
thorough audit of all message content often is required. Data in transit should not be
tampered with, and it should not be possible to pretend to be somebody else. Usually,
it is enough to apply the security measures required for the most sensitive data ele-
ments of the message to the whole message. In some cases, such considerations might
even lead to a different message structure or API refactoring (for instance, splitting
endpoints or operations [Stocker 2021b]). For instance, when two data elements in
a single message require different security levels (such as different permissions and
roles), it might become necessary to split a complex message into two messages
that are secured in different ways. Usage of Atomic Parameter requires the least
design and processing work compared to the other more complex patterns with
regard to the security level of the different parameters and their semantic proximity,
as discussed in [Gysel 2016].
A problem with the decisions for the preceding patterns is that the API provider
often does not know the use cases that API clients might have (in the future). For
instance, when designing the API, the API provider offering the employee records in
our example might not know which calculations different clients might want to per-
form. Hence, in real-life use, interface refactorings [Stocker 2021a]; Neri 2020] and
extensions are advisable. However, such continuous evolution of the API design has
78 Chapter 3 API Decision Narratives

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.

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of requests for the update customer State Transition Operation,
facing the need to aggregate information about customers,
the API designers at Lakeside Mutual decided to combine the Parameter Tree
and the Atomic Parameter patterns
to achieve an expressive data contract exposing the desired view on the domain
model,
accepting that the nested tree structures have to be serialized and deserialized in
an interoperable manner.

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: Element stereotypes


What do the individual representation elements mean? Which purposes within
the DTRs do they have?
Selecting Message Representation Patterns 79

«Decision»
Meaning of
Stereotypes of
Message
Elements

«Option» «Option» «Option» «Option»


an element an element a structured, data- an element containing
containing a containing a only element metadata annotating
semantically typed unique identifier other elements
hyperlink

«Pattern» «Pattern» «Pattern» «Pattern»


Link Element ID Element Data Element Metadata
Element

Figure 3.12 Element stereotypes decision

A rather common meaning or responsibility of a representation element is that


it is used to transport ordinary application data. For example, consider the data of
an Entity in the domain model if DDD [Evans 2003] is used to structure the business
logic of an application.

Pattern: data ELEmEnt


Problem How can domain/application-level information be exchanged between API
clients and API providers without exposing provider-internal data definitions
in the API? How can API client and API provider be decoupled from a data
management point of view?
Solution Define a dedicated vocabulary of Data Elements for request and response
messages that wraps and/or maps the relevant parts of the data in the business
logic of an API implementation.

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

Unnecessary stateful communication might get introduced, violating SOA principles


and microservices tenets [Zimmermann 2017] and leading to performance issues.
Security and data privacy concerns might also demand a careful selection of Data
Elements in an API. If communication partners receive a lot of detailed data, espe-
cially data elements they do not necessarily need, unwelcome security threats, such
as the risk that data is tampered with, get introduced. In addition, extra data protec-
tion can cause configuration effort.
Any data in an API likely has to be maintained for a long period of time. Because
backward compatibility is desired in many integration scenarios, APIs are hard to
change. Continued testing of all API features is required. Flexibly adapting to contin-
uously changing requirements comes with trade-offs regarding the maintainability
and evolution of the API.
A type of Data Element with metadata contained in it is Metadata Element.

Pattern: mEtadata ELEmEnt


Problem How can messages be enriched with additional information so that receivers can
interpret the message content correctly, without having to hardcode assumptions
about the data semantics?
Solution Introduce one or more Metadata Elements to explain and enhance the other
representation elements that appear in request and response messages. Populate
the values of the Metadata Elements thoroughly and consistently; process them
as to steer interoperable, efficient message consumption and processing.

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.

For an identification scheme used in Id Elements, it is important that they are


accurate in multiple senses such that no ambiguities occur throughout the API life
cycle. Simple schemes with low effort up front, such as flat, unstructured character
strings as identifiers, can lead in the long run to stability issues and thus to more effort
to fix the accumulated technical debt. For example, new requirements can lead to name
changes of elements, and then API versions become incompatible with prior versions.
Thus, if possible, universally unique identifiers (UUIDs) [Leach 2005] are usually better
suited than simpler or only locally unique identifiers. Such identifiers are easily read-
able for machines but usually not for humans, which is another trade-off. Finally, there
might be security concerns, as in many application contexts, it should be impossible or
at least extremely difficult to guess instance identifiers. For UUIDs, this is the case, but
it is not necessarily true for very simple identification schemes.
Remote addressability of identifiers is sometimes important. If so, URIs or
other remote locators can be used as Id Elements. In their context, again, it must
be decided whether speaking names or machine-readable unique identifiers are used
(for example, a UUID can be part of a URI). This leads us to the next special type of
Data Element, elements that provide links.

Pattern: Link ELEmEnt


Problem How can API endpoints and operations be referenced in request and response
message payloads so that they can be called remotely?
Solution Include a special type of Id Element, a Link Element, to request or response
messages. Let these Link Elements act as human- and machine-readable, network-
accessible pointers to other endpoints and operations. Optionally, let additional
Metadata Elements annotate and explain the nature of the relationship.
82 Chapter 3 API Decision Narratives

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.

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of the read customer Retrieval Operation,
facing the need to identify customers uniquely,
the API designers at Lakeside Mutual decided to use a custom implementation of
the Id Element pattern (example: "customerId": "bunlo9vk5f")
to achieve a short, compact, and accurate form of customer identification,
accepting that such ids are not network-addressable and not very readable for
humans.

Interlude: Responsibility and Structure Patterns in the


Lakeside Mutual Case
We have already recorded several of the architectural decisions that the integration
architects and API designers at Lakeside Mutual made. Let us now look at the result-
ing design (so far).
Turning the MDSL snippet from the initial API design in Chapter 2 into imple-
mentation-level classes—and walking through the decisions and pattern selection
options we saw in this chapter so far—we might end up with the CustomerInfor-
mationHolder Spring Boot controller shown in Figure 3.13.
Interlude: Responsibility and Structure Patterns in the Lakeside Mutual Case 83

«Master Data Holder,Information Holder Resource»


CustomerInformationHolder

«Pagination, RetrievalOperation, WishList»


getCustomers(String, int, int, String): PaginatedCustomerResponseDto
«RequestBundle, RetrievalOperation, WishList»
getCustomer(List<String>, List<String>): CustomersResponseDto
«StateTransitionOperation»
changeAddress(CustomerId, AddressDto): AddressDto
updateCustomer(CustomerId, CustomerProfileUpdateRequestDto): CustomerResponseDto
«StateCreationOperation»
createCustomer(CustomerCreationUpdateRequestDto): CustomerResponseDto

«use» «use» «use» «use»


«use»
«Data Element» «Data Element» «Data Element»
CustomerProfileUpdateRequestDto CustomersResponseDto PaginatedCustomerResponseDto
firstName: String
lastName: String «Metadata Element»
... lter: String
limit: int
offset: int
size: int
customers
«Link Element»
links: List<Link>

«Data Element»
«Data Element» customers
CustomerResponseDto
AddressDto
rstName: String
streetAddress: String lastName: String
postalCode: String
city: String «Id Element»
customerId: String

Figure 3.13 Class diagram of the CustomerInformationHolder controller and its


associated data transfer objects (DTOs)

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

Governing API Quality


An API provider must compromise between providing high-quality services and
doing so in a cost-effective way. The patterns in the Quality category address or con-
tribute to the following overarching design issue:

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»

«Domain Class» «Domain Class»


Message Operation
Endpoint-Specific «Domain Class»
Qualities API Provider and
API Client
«Decide for some instances of»

«Decision» «Decision» «Decision» «Decision» «Decision»


Explicit Specification of Metering and Preventing API Communication of Explicit Context
Quality Objectives Charging for API Clients From Errors Representation
and Penalties Consumption Excessive Usage

«Consider If Not
Decided Yet»
«Consider If Not «Consider If Not
Decided Yet» Decided Yet»
«Decision»
Client Identification
and Authentication

Figure 3.14 Decisions about API quality and its governance


Governing API Quality 85

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:

• Identification and authentication of the API client


• Metering and charging for API consumption
• Preventing API clients from excessive API usage
• Communication of errors
• Context representation

Identification and Authentication of the API Client


Identification means distinguishing which client is interacting with the API; authen-
tication refers to validating an identity provided to the API. Identification and
authentication are important for providers of APIs that are paid for (and/or use free-
mium models) in order to establish authorization: once an API client is identified
and authenticated, the API provider grants access based on the API client’s proven
identity and its authorization rights. For example, an API provider of a commercial
API offering must identify its clients to decide whether a call actually originates from
a known client (such as a paying customer) or from an unknown one.
Authentication and authorization are important for ensuring security, but they
also enable measures for ensuring many other qualities. For instance, the perfor-
mance of the overall system can degrade if unknown clients can access the API with-
out control or if known clients are able to make excessive use of the API. In such
situations, reliability is threatened or operating costs may rise unexpectedly.
QoS-related factors such as performance, scalability, and reliability can be ensured
or monitored to a certain extent by the API provider and API client. In addition, they
can be guaranteed in QoS guarantees to the API client. Such guarantees are usually
related to some notion of pricing scheme or subscription model of the client, and
this requires API client identification and authentication as well.
In summary, client identification and authentication are the foundations for
achieving certain security qualities and support many techniques to establish QoS
and cost control. The typical decision to be made in this context is shown in Figure
3.15. Its link to other decisions and practices is apparent in Figure 3.14, which shows
that several decisions require us to consider client identification and authentication.
86 Chapter 3 API Decision Narratives

«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

«Option» «Option» «Option» «Includes»


«Has Variant» identification and no secure identification and identification and
authentication via authentication needed authentication via
shared secret dedicated protocol

«Pattern» «Do Nothing» «Practice»


API Key Do Nothing Authentication
Protocol

«Realizes» «Realizes»
«Practice»
Authentication

Figure 3.15 Client identification and authentication decision

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.

Pattern: aPi kEy


Problem How can an API provider identify and authenticate clients and their requests?
Solution 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.

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

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of the Community API for Frontend Integration for customer
management,
facing the need to protect sensitive personal information such as customer records,
the API designers at Lakeside Mutual decided for the API Key pattern
to achieve that only identified clients can access the API,
accepting that API Key management is required, which adds operational cost,
and also accepting that this is only a basic security solution.

Metering and Charging for API Consumption


If the API is a commercial offering, the API provider might want to charge for its
usage. Thus, a means for identifying and authenticating clients is required. Usually,
existing authentication practices are used. Then the provider can monitor clients and
assign a Pricing Plan for the API usage.

$$$

Pattern: PriCing PLan


Problem How can the API provider meter API service consumption and charge for it?
Solution 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.

Again, we can alternatively not meter and charge the customer.


Figure 3.17 illustrates possible variants of the Pricing Plan pattern: pricing can
be based on actual usage, on some kind of market-based allocation (such as auc-
tions), or on flat-rate subscriptions. Each of these variants can be combined with a
freemium model. In the context of a Pricing Plan, sometimes a Rate Limit is used
to ensure fair use. Figure 3.16 illustrates the metering and charging for API consump-
tion decision.
Governing API Quality 89

«Decision»
Metering and
Charging for API
Consumption

«Option» «Option»
Yes No «Consider If Not Decided Yet»

«Pattern» «Do Nothing» «Decision»


Pricing Plan Do Nothing Client
Identification
and
Authentication

«Can Use» «Can Use»

«Pattern» «Practice»
Rate Limit Authentication

«Can Use»

Figure 3.16 Metering and charging for API consumption decision

«Pattern» «Pattern»
Pricing Plan Freemium Model
«Can Be Combined With»

«Has Variant» «Has Variant» «Has Variant»

«Pattern» «Pattern» «Pattern»


Flat-Rate Usage-based Market-based
Subscription Pricing Pricing

Figure 3.17 PRICING PLAN variants


90 Chapter 3 API Decision Narratives

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.

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of the customer self-service channel,
facing the need to attract and retain customers,
the API designers at Lakeside Mutual decided not to introduce a Pricing Plan
but offer their API at no charge
to achieve API acceptance and success,
accepting that the API has to be funded in other ways.

Preventing API Clients from Excessive API Usage


Excessive use of an API by a few clients can significantly limit the usefulness of the
service for other clients. Simply adding more processing power, storage space, and
network bandwidth to solve the problem is usually not viable economically. There-
fore, preventing excessive API usage by clients often is in order. Once API clients can
be identified, their individual usage of the API can be monitored; the typical way to
perform identification is authentication of clients, as explained earlier. The Rate
Limit pattern addresses the problem of excessive API use by limiting the number of
requests per period of time allowed.

Pattern: ratE Limit


Problem How can the API provider prevent API clients from excessive API usage?
Solution Introduce and enforce a Rate Limit to safeguard against API clients that overuse
the API.
Governing API Quality 91

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

«Option» «Option» «Consider If Not Decided Yet»


Yes No

«Pattern» «Do Nothing» «Decision»


Rate Limit Do Nothing Client
Identification
and
Authentication

«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.

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of the customer self-service channel,
facing the need to attract and retain customers,
the API designers at Lakeside Mutual decided for the Rate Limit pattern
to achieve fair workload distribution,
accepting that the chosen Rate Limit has to be enforced, which causes implemen-
tation effort and will slow down demanding API clients hitting their limits.

Explicit Specification of Quality Objectives and Penalties


Quality objectives are kept implicit and vague for many APIs. If the client requires (or
even pays for) stronger guarantees or the provider wants to make explicit guarantees,
for instance, as differentiation from competitors, an explicit specification of quality
objectives and penalties can be valuable. An instance of the Service Level Agreement
pattern as a more formal extension and complement of the API Description (and thus
of the API contract) detailing measurable service-level objectives (SLOs) and (option-
ally) penalties in case of violations provides a way to compile such specifications.

Pattern: sErViCE LEVEL agrEEmEnt


Problem How can an API client learn about the specific quality-of-service characteristics
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?
Solution As an API product owner, establish a structured, quality-oriented Service Level
Agreement that defines testable service-level objectives.

The decision about introducing a service-level agreement (SLA) is shown in


Figure 3.19. To make an SLA unambiguous, it must identify the specific API
operation(s) that it pertains to and must contain at least one measurable SLO. An
SLO specifies a measurable aspect of the API, such as performance or availability.
Governing API Quality 93

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»

«Pattern» «Do Nothing» «Decision»


Service Level Do Nothing Client
Agreement Identification
and
Authentication

«Has Variant» «Has Variant» «Has Variant» «Can Use»

«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

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of all insurance management APIs,
facing the need to coordinate API client and provider development,
the API designers at Lakeside Mutual decided against an explicit service-level
agreement (“do nothing”)
to achieve that the documentation and operations overhead is kept light,
accepting that clients’ expectations might not match the QoS that they can actu-
ally experience.

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.

Pattern: Error rEPort


Problem How can an API provider inform its clients about communication and
processing faults? How can this information be made independent of the
underlying communication technologies and platforms (for example, protocol-
level headers representing status codes)?
Solution 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 end users such
as administrators.
Governing API Quality 95

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

«Option» «Option» «Option»


Perform API-level Communicate errors Provide no specific
error reporting only using the solution for
application or communicating
transport protocol errors
error codes

«Do Nothing»
Error Reporting Protocol-Level
Do Nothing
Error Codes
«Can Be Combined With»

Figure 3.20 Communicate errors decision


96 Chapter 3 API Decision Narratives

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of all Backend Integration APIs,
facing the need to operate reliably even in case of failures,
the API designers at Lakeside Mutual decided to use the Error Report pattern
to achieve that clients can use the reported error information to decide on their
reactions,
accepting that the reports have to be prepared and processed and that response
message size will increase.

Explicit Context Representation


In some messages, in addition to ordinary data, context information has to be
exchanged between client and provider. Examples of context information are loca-
tion and other API user information, the preferences forming a Wish List, or security
information such as login credentials used for authentication, authorization, and
billing (for instance, including an API Key).
To promote protocol independence and a platform-independent design, there is
an alternative to the default use of standard headers and header extension capabil-
ities of the networking protocol: each message can be enhanced with a Context
Representation in the message body. Figure 3.21 shows the decision between the
default choice (“do nothing”) and the alternative, pattern-based solution. Here, “do
nothing” means either that no context information is sent at all or that the context
information is sent as part of the protocol header and not made explicit in the mes-
sage payload.

«Decision»
Exchange of
Context
Information
Required

«Option» «Option»
Yes No

«Pattern» «Do Nothing»


Context Do Nothing
Representation

Figure 3.21 CONTEXT REPRESENTATION decision


Governing API Quality 97

Decision: Context representation


Is the exchange of explicit context information adequate?
This choice decides for or against the Context Representation pattern.

Pattern: ContEXt rEPrEsEntation


Problem How can API consumers and providers exchange context information without
relying on any particular remoting protocols? How can identity information
and quality properties in a request be made visible to related subsequent ones in
conversations?
Solution Combine and group all Metadata Elements that carry the desired information
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 Context Representation accordingly. Position and mark
the consolidated Context Representation element so that it is easy to find and
distinguish from other Data Elements.

Interoperability and technical modifiability can be enhanced if context informa-


tion is transported outside of protocol-level headers. Otherwise, it becomes diffi-
cult to ensure that context information exchange can pass each kind of intermediary,
such as “Proxies” [Gamma 1995] and “API Gateways” [Richardson 2016] in a dis-
tributed system. When protocols are upgraded, the availability and semantics of pre-
defined protocol headers may change. In addition, Context Representation helps
to cope with the diversity of protocols to be supported in many distributed appli-
cations, which in turn can help to improve evolvability and lessen dependencies on
technologies. The pattern can increase developer productivity:
Using protocol headers is convenient and makes it possible to leverage protocol-
specific frameworks, middleware, and infrastructure (such as load balancers and
caches) but delegates control to the protocol designers and implementers. By con-
trast, a custom approach maximizes control but causes development and test effort.
To achieve end-to-end security, tokens and digital signatures have to be trans-
ported across multiple nodes. Such security credentials are a type of control metadata
that the consumer and provider have to exchange directly; involving intermediaries
and protocol endpoints would break the desired end-to-end security. Similarly, log-
ging and auditing information is critical context data that should be transported end
to end without any interference from intermediaries.
98 Chapter 3 API Decision Narratives

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of its Backend Integration APIs,
having to cross technology boundaries to satisfy end-to-end quality of service
needs,
the API designers at Lakeside Mutual decided to introduce an explicit Context
Representation
to achieve that client can find all metadata in one place,
accepting that the underlying network might not have access to the context data
in the payload.

This decision narrative covered the theme API quality governance; the next set of
decisions aims at improving certain qualities, such as performance.

Deciding for API Quality Improvements


The previous section dealt with quality governance and management; in this section,
we investigate quality improvements. We start with pagination and then investigate
other ways to avoid unnecessary data transfer and how to handle referenced data in
messages.

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

«Optional Next» «Optional Next»

«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» «Pattern» «Pattern» «Pattern»


Page-Based Cursor-Based Offset-Based Time-Based
Pagination Pagination Pagination Pagination

Figure 3.22 PAGINATION decision

Decision: Pagination decisions


Does a data structure to be transmitted to API clients contain a large number of
data records with the same structure? If yes: For the task of the API client, are
only a few data records required?
100 Chapter 3 API Decision Narratives

If both conditions apply, the Pagination pattern is eligible.

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.

Figure 3.23 shows the pattern relations of Pagination.

«Pattern»
Pagination

«Can Use» «Can Use» «Can Use»


for output pages for output pages for input query parameters

«Pattern» «Pattern» «Pattern»


Parameter Tree Parameter Forest Atomic
Parameter List

Figure 3.23 PAGINATION dependencies

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.

In addition to index-and page-based Pagination, the pattern has three variants:

• Offset-Based Pagination: Compared to simple pages, an offset specified by


the API client enables more flexibility in controlling the number of requested
results or changes in the page size.
• Cursor-Based Pagination: This variant does not rely on the index of an element
but instead on a cursor that the API client can control.
• Time-Based Pagination: This variant is similar to Cursor-Based Pagination but
uses timestamps instead of cursors to request chunks.

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

Underlying network transports, such as IP networking, transport data in packets,


which leads to nonlinear transfer times with data size. For example, 1500 bytes fit
into a single IP packet transmitted over Ethernet [Hornig 1984]. As soon as the data
is one byte longer, two separate packets have to be transmitted and reassembled on
the receiver side.
From a security standpoint, retrieving and encoding large data sets can incur
high effort and cost on the provider side and can thus open up an attack vector for a
denial-of-service attack. Moreover, transferring large data sets across a network can
lead to interruptions because networks are not guaranteed to be reliable, especially
cellular networks.
Finally, compared to using the Parameter Tree and Parameter Forest patterns
without Pagination, the pattern is substantially more complex to understand and
thus can be less convenient to developers and generally requires more experience.

Sample decision outcome. The API designers at Lakeside Mutual decided as


follows:
In the context of the retrieval operations in the Customer Core Master Data
Holder,
facing the need to balance the number of requests/responses and message sizes,
the API designers at Lakeside Mutual decided to use the cursor-based variant of
the Pagination pattern
to achieve slicing of large data sets in responses,
accepting that these request-response pairs have to be coordinated, which requires
control metadata.

Other Means of Avoiding Unnecessary Data Transfer


Sometimes unnecessary data is transferred when API operations are called. We
already learned about Pagination as an option to reduce response message sizes.
Four more patterns address such situations.
Most API quality aspects discussed earlier can be decided for broader groups of
API and client combinations (such as all clients who have freemium API access). In
contrast, the decisions about patterns in this section must be made per operation,
as only an analysis of the individual information needs of the clients of a particular
operation can indicate whether or not the data transfer can be reduced.
Deciding for API Quality Improvements 103

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.

Pattern: WisH List


Problem How can an API client inform the API provider at runtime about the data it is
interested in?
Solution 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”).

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.

Pattern: WisH tEmPLatE


Problem How can an API client inform the API provider about nested data that it is
interested in? How can such preferences be expressed flexibly and dynamically?
Solution Add one or more additional parameters to the request message that mirror the
hierarchical structure of the parameters in the corresponding response message.
Make these parameters optional or use Boolean as their types so that their values
indicate whether or not a parameter should be included.

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

Let us consider another situation in which an analysis of the usage of the


operations of an API provider shows that some clients keep requesting the same
server-side data. The requested data changes much less frequently than the client’s
send requests. In such cases, we can avoid unnecessary data transfer by using a
Conditional Request.

Pattern: ConditionaL rEquEst


Problem How can unnecessary server-side processing and bandwidth usage be avoided
when frequently invoking API operations that return rarely changing data?
Solution Make requests conditional by adding Metadata Elements to their message
representations (or protocol headers) and processing these requests only if the
condition specified by the metadata is met.

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.

Pattern: rEquEst bundLE


Problem How can the number of requests and responses be reduced to increase
communication efficiency?
Solution Define a Request Bundle as a data container that assembles multiple
independent requests in a single request message. Add metadata such as
identifiers of individual requests and bundle element counter.
Deciding for API Quality Improvements 105

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

«Do Nothing» «Pattern» «Pattern» «Pattern» «Pattern»


Do Nothing Wish List Wish Template Conditional Request Bundle
Request

«Influences» «Influences» «Influences» «Influences»

«Pattern»
Rate Limit

Figure 3.24 Avoid unnecessary data transfer decision

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

«Can Be Combined With»

«Can Be Combined With» «Can Be Combined With»


«Pattern»
Conditional
Request

«Pattern» «Pattern»
Wish List Wish Template
«Can Be Combined With» «Can Be Combined With»

Figure 3.25 Avoid unnecessary data transfer: Pattern combinations

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

names might be used to introduce an API-specific form of denial-of-service attack.


Data that is not transferred cannot be stolen and cannot be tampered with. Finally,
complicating the API—as all four patterns do—increases the complexity of API cli-
ent programming. The currently trending GraphQL technology can be seen as an
extreme form of declarative Wish Template. In addition, special invocation cases
introduced by the patterns require more testing and maintenance efforts.

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.

Handling Referenced Data in Messages


Not every Data Element in a message can be represented as a plain data record, as
some data records contain references to other data records. An important question is
how these local data references should be reflected in the API; answers to it deter-
mine the API granularity and its coupling characteristics.

Decision: Handling of referenced data


How should referenced data in data records be represented in the API?
108 Chapter 3 API Decision Narratives

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»

Figure 3.26 Handling of referenced data decision

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.

Pattern: EmbEddEd Entity


Problem How can one avoid sending multiple messages when their receivers require
insights about multiple related information elements?
Solution For any data relationship that the client wants to follow, embed a Data Element
in the request or response message that contains the data of the target end of the
relationship. Place this Embedded Entity inside the representation of the source
of the relationship.
Deciding for API Quality Improvements 109

The alternative is to make the referenced data accessible remotely and point at it,
introducing a Link Element to the message:

Pattern: LinkEd information HoLdEr


Problem How can messages be kept small even when an API deals with multiple
information elements that reference each other?
Solution Add a Link Element to messages that pertain to multiple related information
elements. Let this Link Element reference another API endpoint that represents
the linked element.

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.

Decisions about API Evolution


To be successful, APIs should expose stable contracts serving as a baseline for build-
ing applications on top of them; developer expectations and delivery guarantees have
to be balanced. APIs must be maintained, and they have to evolve while fixing bugs
and adding features. The evolution of an API requires that API providers and clients,
who usually follow different life cycles [Murer 2010], establish rules and policies to
ensure that (1) the provider can improve and extend the API and its implementation,
and (2) the client can keep functioning with no or few required changes for as long as
possible. Modifying an API might lead to client-breaking changes. However, break-
ing changes should be minimized, as they cause migration efforts for a potentially
large (and sometimes unknown) number of clients. If required changes cause API
version upgrades, these changes and upgrades have to be managed and communi-
cated well to reduce the associated risk and cost.
Decisions about API Evolution 111

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

«Decision» «Decision» «Decision»


Versioning and Version Offering an
Compatibility Introduction and Experimental
Management «Optional Next» Decommissioning «Optional Next» Preview

«Decide for some instances of» «Decide for some instances of» «Decide for some instances of»

«Basic Concept»
API

Figure 3.27 Evolution category


112 Chapter 3 API Decision Narratives

Versioning and Compatibility Management


An important early decision regarding API evolution is how versioning should be
supported. In rare cases, even not versioning at all might be an option—consider, for
instance, proof-of-concept, experimental preview, or hobby projects.

Decision: Versioning and compatibility management


Should API versioning and compatibility management be supported? How should
it be supported?

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.

«Decision» «Basic Concept»


Versioning and API
Compatibility
Management «Decide for some instances of»

«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

«Do Nothing» «Pattern» «Pattern» «Pattern»


No Versioning Semantic Version Identifier API Description
Scheme Defined Versioning
«Can Be Combined With» «Includes»

«Can Use»
to transmit identifier in a message

«Pattern»
Metadata
Element

Figure 3.28 Versioning and compatibility management decision

Version Identifier defines how explicit version numbers are transmitted in


APIs in order to indicate the API version. The related decision asks whether such
an explicit versioning and version transmission scheme should be introduced.
Important qualities that one can achieve by applying the pattern are accuracy and
Decisions about API Evolution 113

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.

Pattern: VErsion idEntifiEr


Problem How can an API provider indicate its current capabilities as well as the existence
of possibly incompatible changes to clients in order to prevent malfunctioning of
clients due to undiscovered interpretation errors?
Solution 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.

Version Identifiers are typically specified in the API Description. In general,


all patterns in this category are closely related to the API Description. They can be
used to initially specify the API version and provide a mechanism to not only define
syntactical structure (the technical API contract) but also cover organizational mat-
ters such as ownership, support, and evolution strategies.
There are many possible ways to include Version Identifiers in messages. A sim-
ple, technology-independent way is to define a Metadata Element as a special place
in the message body to hold the Version Identifier; this special place can be part
of a dedicated Context Representation. Protocol headers and endpoint addresses
such as URLs are possible alternatives.
While there are many conventions that can be followed, Version Identifier is
often used in conjunction with Semantic Versioning. The Semantic Version-
ing pattern describes a way in which compound version numbers can be defined,
expressing backward compatibility and the impact of functional changes via major,
minor, and patch versions.
114 Chapter 3 API Decision Narratives

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.

Pattern: sEmantiC VErsioning


Problem How can stakeholders compare API versions to detect immediately whether they
are compatible?
Solution Introduce a hierarchical three-number versioning scheme x.y.z, which allows
API providers to denote different levels of changes in a compound identifier. The
three numbers are usually called major, minor, and patch versions.

In Semantic Versioning only minimal effort to detect version incompatibility is


required, especially for clients, and more clarity of change impact can be achieved by
just looking at the parts of the Version Identifier. A well-known Semantic Ver-
sioning scheme, such as the hierarchical three-number versioning scheme, can help
to achieve a clear separation of changes with different levels of impact and compat-
ibility. This brings clarity with regard to the evolution timeline of the API. In addi-
tion, the change impact caused by the release of a new API version should be clear to
the API client and provider developers.
API providers must be careful not to support too many API versions at the same
time, and a fine-grained versioning scheme can tempt them to do just that. The
manageability of API versions and related governance effort for the API provider
are important: more APIs, parallel API versions, and extended guarantees made to
clients mean more API management and governance effort.

Sample decision outcome. The API product manager at Lakeside Mutual


decided as follows:
In the context of the offer quotation features in the policy management API,
facing the need to integrate third-party developers and satisfy auditing
requirements,
the API designers at Lakeside Mutual decided to combine the Version Identifier
pattern and the Semantic Versioning pattern
Decisions about API Evolution 115

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.

Strategies for Commissioning and Decommissioning


Many API providers are eager to bring new versions to production quickly. However,
they often overlook the importance of the ability to decommission old versions in
order not to be overwhelmed with maintenance effort and resulting cost.
If new API versions are developed and deployed in production, different strategies
for introducing the new versions and decommissioning old ones exist. This section
covers the following decision:

Decision: Version introduction and decommissioning


When and how should new versions of an API be introduced and old versions be
decommissioned?

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.

«Decision» «Basic Concept»


Version API
Introduction and
Decommissioning «Decide for some instances of»

«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

«Pattern» «Pattern» «Pattern»


Two in Limited Lifetime Aggressive
Production Guarantee Obsolescence

Figure 3.29 Version introduction and decommissioning decision

The first option is to give a Limited Lifetime Guarantee, which establishes a


fixed time range for the lifetime of an API version after its initial release.
116 Chapter 3 API Decision Narratives

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.

Pattern: aggrEssiVE obsoLEsCEnCE


Problem How can API providers reduce the effort for maintaining an entire API or
its parts (such as endpoints, operations, or message representations) with
guaranteed service quality levels?
Solution Announce a decommissioning date to be set as early as possible for the entire API
or its obsolete parts. Declare the obsolete API parts to be still available but no
longer recommended to be used so that clients have just enough time to upgrade
to a newer or alternative version before the API parts they depend on disappear.
Remove the deprecated API parts and the support for it as soon as the deadline
has passed.
Decisions about API Evolution 117

Compared to all other options in this decision, Aggressive Obsolescence radi-


cally minimizes the maintenance effort for the API provider. Virtually no support for
old clients must be provided. However, for clients that do not follow the same life
cycle as the provider, this pattern forces changes to clients in a given time span as a
consequence of the API changes. As this might not always be possible, clients might
break. This pattern acknowledges or respects the power dynamics between API pro-
vider and client, but here the API provider is the “strong” partner in the relationship
and can dictate when changes will happen. This often has to be viewed in the light of
commercial goals and constraints of the API provider. For example, if revenues from
the API are small and many clients have to be supported, the API provider might not
be able to sustain other lifetime guarantees.
The Two in Production pattern defines a rather strict strategy of how many
incompatible versions should be kept active at the same time.

v1.3 v2.1

Pattern: tWo in ProduCtion


Problem 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?
Solution Deploy and support two versions of an API endpoint and its operations that
provide variations of the same functionality but do not have to be compatible
with each other. Update and decommission the versions in a rolling, overlapping
fashion.

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).

Decision: Using an experimental preview


Should a new version of an API or a new API have an experimental preview?

Figure 3.30 illustrates the rather straightforward decision of allowing or disallow-


ing an Experimental Preview.

«Decision» «Basic Concept»


Offering an API
Experimental
Preview «Decide for some instances of»

«Option»
Do not offer «Option»
API previews Offer API previews

«Do Nothing» «Pattern»


No Experimental Experimental
Preview Preview

Figure 3.30 Using an additional experimental preview decision

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.

This pattern can be seen as an additional consideration to the strategies in the


version introduction and decommissioning strategies decision presented earlier, as
the Experimental Preview can be offered instead of a full-fledged additional ver-
sion. That is, the decision about an additional experimental preview can be taken as
a follow-on when a decision on versioning and decommissioning strategies has been
made already. In addition, in any of the other strategies or even without any such
strategy in place, Experimental Preview can be used as well, such as to support
experimenting with the API and gathering early feedback. For instance, an Experi-
mental Preview can be used in the initial phase of a new version introduced in the
context of Two in Production, which then, once it has matured enough, transits to
become one of the two supported versions in production.

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

Interlude: Quality and Evolution Patterns in the


Lakeside Mutual Case
The Lakeside Mutual developers applied many of the quality patterns in the various
services. To serve multiple clients with different information needs, Wish Lists are
introduced so that clients can retrieve exactly the data they need. For example, a cli-
ent might need postal codes and birthdays of customers for a statistical survey, but
not the full address:

curl -X GET --header 'Authorization: Bearer b318ad736c6c844b'\


http://localhost:8080/customers/gktlipwhjr?\
fields=customerId,birthday,postalCode

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:

curl -X GET --header 'Authorization: Bearer b318ad736c6c844b'\


http://localhost:8080/customers/invalid-customer-id

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:

curl -X GET http://localhost:8090/customers/rgpp0wkpec


{
"customerId": "rgpp0wkpec",
...
"_links": {
...
"policies": {
"href": "/customers/rgpp0wkpec/policies"
}
}
}

Policies can then be requested separately:

curl -X GET http://localhost:8090/customers/rgpp0wkpec/policies


[ {
"policyId": "fvo5pkqerr",
"customer": "rgpp0wkpec",
"creationDate": "2022-02-04T11:14:49.717+00:00",
"policyPeriod": {
"startDate": "2018-02-04T23:00:00.000+00:00",
"endDate": "2018-02-09T23:00:00.000+00:00"
},
"policyType": "Health Insurance",
"deductible": {
"amount": 1500.00,
"currency": "CHF"
},
...
122 Chapter 3 API Decision Narratives

Enforcing the decisions for Version Identifier, Semantic Versioning, Experi-


mental Preview, and Two in Production, the API owners, architects, and develop-
ers at Lakeside Mutual might add identifiers such as v1.0 to the URIs and use the
release management capabilities of their source code repository and collaboration
platform. The versioning and life-cycle management decisions are not shown in the
code snippets in this interlude.
Assuming that git is the chosen version-control system providing the source code
repositories, there could be two production branches and an experimental one. Each
of these branches could feed a different continuous integration and continuous deliv-
ery/continuous deployment (CI/CD) pipeline ending with a deployment (for test or
production, respectively).
More details on the implementation of Lakeside Mutual can be found in Appen-
dix B, “Implementation of the Lakeside Mutual Case.” Note that not all decisions
from this chapter are fully implemented; the case study implementation continues to
evolve.3

Summary
In this chapter, we identified pattern-related architectural decisions required during
API design and evolution, covering the following topics:

• Selection of foundation patterns characterizing the visibility (public, commu-


nity, solution-internal) and type of APIs (frontend vs. backend integration)
• Selecting endpoint roles and operation responsibilities that differ in their
nature (activity vs. data orientation) and impact on provider-side state (read
and/or write access)
• Choosing structure-related patterns that describe the individual message ele-
ments syntactically (flat and nested parameters) and semantically (element ste-
reotypes such as data, metadata, identifier, and link element)
• Deciding about API quality governance and management (for instance,
Service Level Agreements)
• API quality patterns to improve performance and rightsize messages including
Pagination and Wish List

3. Are the Lakeside Mutual developers somewhat disconnected from the architects and the product owner
of this sample case?
Summary 123

• Agreeing on suitable API lifetimes and approaches to versioning during API


evolution
• Documenting API contracts and descriptions minimally or elaborately, includ-
ing technical and commercial aspects such as billing

Each of our 44 patterns appears as an option (or alternative) in the architectural


decision questions presented; its pros and cons with regard to design forces consti-
tute the decision criteria. We used the Lakeside Mutual case study to provide exem-
plary decision outcomes, captured as why-statements.
This completes the introductory Part 1 of our book; the reference Part 2 contains
the pattern texts and a pattern language overview.
This page intentionally left blank
Part 2

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:

• Chapter 4, “Pattern Language Introduction,” provides a pattern language


overview and introduces foundation and basic structure patterns that serve as
building blocks of the patterns in the subsequent chapters.
• Chapter 5, “Define Endpoint Types and Operations,” discusses endpoint
roles and operation responsibilities, taking a conceptual architecture view on
API design and evolution.
• Chapter 6, “Design Request and Response Message Representations,” is
about request and response message structures, targeting integration architects
and developers.
• Chapter 7, “Refine Message Design for Quality,” presents patterns that
improve message structures with respect to certain qualities. This chapter also
targets architects and developers.
• Chapter 8, “Evolve APIs,” discusses API evolution and life-cycle manage-
ment. The API product manager comes in as an additional targeted role.
• Chapter 9, “Document and Communicate API Contracts,” covers API doc-
umentation and commercial aspects. It is relevant for all roles, API product
managers in particular.

Let’s get started with the pattern overview and orientation.


Chapter 4

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

Positioning and Scope


According to our domain model, established in Chapter 1, “Application Program-
ming Interface (API) Fundamentals,” API clients and providers exchange request and
response messages to call operations in API endpoints. Many of our patterns focus
on the payload content of such messages that contain one or more representation
elements, possibly nested. Enterprise Integration Patterns [Hohpe 2003] offers three
alternative patterns about this message content: “Document Message,” “Command
Message,” and “Event Message.” In messaging systems, such messages travel from
the sending endpoint to the receiving endpoint over communication “Channels.”
These Channels may be offered by queue-based messaging systems but also come as
HTTP connections or other use integration technologies, such as GraphQL and
gRPC. Protocol capabilities and configuration, as well as message size and content
structure, influence the quality properties of an API and its implementation. In this
messaging context, APIs can be seen as “Service Activators” [Hohpe 2003]—viewed
from the communication channels, they serve as “Adapters” [Gamma 1995] for the
application services available in the API implementation.
In our pattern language, we look into the command, document, and event mes-
sages in terms of their inner structures. We also investigate the roles played by
representation elements, operations, and API endpoints—irrespective of the com-
munication protocols used. We discuss how to group messages into endpoints to
achieve suitable API granularity and coupling, how to document APIs, and how to
manage the evolution of API endpoints and their parts.
We are particularly interested in message payloads that are exchanged as JSON
objects—for instance, via HTTP GET, POST, and PUT—and in message queues
offered by cloud providers or messaging systems (such as ActiveMQ or RabbitMQ).
JSON is a popular message exchange format in Web APIs; our patterns work equally
well when XML documents or other text structures are exchanged. They can even be
applied to define the content of messages with binary encodings.
Figure 4.1 visualizes the scope of our patterns in a Web API example. An HTTP
GET, shown as a curl command, asks for information about a single customer,
rgpp0wkpec, of Lakeside Mutual (the case introduced in Chapter 2, “Lakeside
Mutual Case Study”).
The exemplary response message is nested: the customer information contains
not only the birthday but also a log of address changes in the form of a moveHis-
tory. Indicated by the JSON array notation [...], a collection of relocation
moves could be returned (in the example, the array contains only one move destina-
tion). Each move destination is characterized by three strings, "city", "postal-
Code", "street-Address", wrapped in the JSON object notation {...} in the
figure. This two-level structure raises an important, recurring API design issue:
Positioning and Scope 129

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

Consumer API Provider

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.”

Patterns: Why and How?


Patterns can help resolve API design issues, presenting proven solutions to problems
recurring in a particular context (here, API design and evolution). Patterns are plat-
form-independent by definition, thus avoiding concept, technology, and vendor lock-
in. They form a common language for a domain. Adequate pattern usage can make
the designs that adopt them easier to understand, port, and evolve.
Each pattern text can be seen as a small, specialized, standalone article. These
texts are structured according to a common template:

• 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).

Navigating through the Patterns


When we decided how to organize our patterns, we looked at two other books for
inspiration: Enterprise Integration Patterns [Hohpe 2003] is organized by the life
cycle of messages traveling through a distributed system, from creation and sending
to routing, transforming, and receiving. Patterns of Enterprise Application Architec-
ture [Fowler 2002] uses logical layers as a chapter and topic breakdown, progressing
from domain layer to persistence layer and presentation layer.
Regrettably, neither layers nor life cycles alone seemed to work well for the API
domain. Hence, we could not decide on one best way to organize but offer multiple
ones to guide you through the patterns: architectural scope (as defined by the API
domain model from Chapter 1), topic categories, and refinement phases.1

Structural Organization: Find Patterns by Scope


Most of our patterns focus on API building blocks at different levels of abstraction
and detail; some concern the API as a whole and its documentation, both technical
and commercial. The resulting architectural scopes are API as a whole, endpoint,
operation, and message. We introduced these basic concepts in the API domain
model in Chapter 1. Figure 4.2 calls out patterns for these five scopes.

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

Message-Level Patterns Message-Level Patterns


(typically in request and (most impact on response):
response): * Pagination
* Data Element * Embedded Entity
* Metadata Element * Linked Information Holder
* Identifier Element * Error Report
* Link Element

Figure 4.2 Patterns by domain model element and architectural scope

Patterns such as API Description and Service Level Agreement concern


the API as a whole. Others, such as Processing Resource and Data Transfer
Resource, operate on single endpoints. Many patterns deal with operation or mes-
sage design; some of these primarily target request messages (API Key, Wish List),
and others are more focused on response messages (Pagination, Error Report).
Element stereotypes may appear both in requests and responses (Identifier Ele-
ment, Metadata Element).

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.

Theme Categorization: Search for Topics


We grouped the patterns into five categories. Each category answers several related
topical questions:

• Foundation patterns: Which types of systems and components are integrated?


From where should an API be accessible? How should it be documented?
Navigating through the Patterns 133

• 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?

These theme categories organize the decision models in Chapter 3, “API


Decision Narratives,” and the Web site supporting this book.2 Figure 4.3 groups
the patterns by book chapter. The theme categories and Chapters 4 to 8 corre-
spond with each other but for only two exceptions: API Description from the
foundation category and three patterns related to quality management (Rate
Limit, Pricing Plan, Service Level Agreement) are factored out into a separate
Chapter 9, “Document and Communicate API Contracts.” The patterns API Key,
Error Report, and Context Representation are related to quality but appear
in Chapter 6, “Design Request and Response Message Representations,” due to
their role of special-purpose representations. The cheat sheet in Appendix A fol-
lows the same structure.

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

Frontend Backend Atomic Atomic Parameter Parameter


Integration Integration Parameter Parameter Tree Forest
List

5
Define Endpoint Types
and Operations

Public Community Solution


API API Internal API

6
Design Request and Response
Message Representations Information Processing Data Transfer
Holder Resource Resource
Resource

API Key Error Context


Report Representation Computation Link Lookup
Function Resource

Data Metadata Id Element Link Element State Creation Retrieval State Transition
Element
Eleme Element Operation Operation Operation

7
Refine Message Design for Quality

Operational Master Reference


Data Holder
H Data Holder Data Holder
Conditional Request Linked Embedded d
Request Bundle Information Entity
8
Evolve APIs
Holder

v0.1
v1.2 v1.3 v2.1

Pagination ?
Wish List Wish Template
Experimental Aggressive Two in

9 Document API Contracts Preview Obsolescence Production

v1.1

API Service Level Pricing Plan Rate Limit Limited Version Semantic
Description Agreement Lifetime Identifier Versioning
Guarantee

Figure 4.3 Patterns by chapter


Navigating through the Patterns 135

Time Dimension: Follow Design Refinement Phases


Roughly following the “Unified Process” [Kruchten 2000], an API design evolves
from project/product inception to design elaboration, implementation construction
iterations, and project/product transition. Table 4.1 categorizes patterns by process
phases; note that some patterns can be applied in multiple phases.

Table 4.1 Patterns by Phase


Phase Category Patterns
Inception Foundation Public API, Community API, Solution-Internal API
Backend Integration, Frontend Integration
API Description
Elaboration Responsibility Information Holder Resource, Processing Resource
Master Data Holder, Operational Data Holder, Reference
Data Holder
Data Transfer Resource, Link Lookup Resource
Quality API Key, Context Representation, Error Report
Construction Structure Atomic Parameter, Atomic Parameter List, Parameter Tree,
Parameter Forest
Data Element, Id Element, Link Element, Metadata Element
Responsibility State Creation Operation, State Transition Operation
Retrieval Operation, Computation Function
Quality Pagination
Wish List, Wish Template
Embedded Entity, Linked Information Holder
Conditional Request, Request Bundle
Transition Foundation API Description
Quality Service Level Agreement, Pricing Plan, Rate Limit
Evolution Semantic Versioning, Version Identifier
Aggressive Obsolescence, Experimental Preview
Limited Lifetime Guarantee, Two in Production

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.

How to Navigate: The Map to MAP


You can use the three navigation aids structure from this section—structure/scope,
theme category/chapter, and time/phase—to explore the language for your immedi-
ate needs if you are not yet ready to read Part 2 page by page. Having picked one or
more entry points, you can then follow the “Related Patterns” pointers provided in
each pattern to move on; you can also return to one of the three organizers (scope,
topic, phase). Having studied a few patterns, you may want to check out the Lakeside
Mutual case study or the real-world pattern stories in Chapter 10, “Real-World Pat-
tern Stories,” to return to the big picture and learn how individual patterns can be
combined.
The following section introduces basic API foundation and message structure
patterns eligible during the Align phase of ADDR, with Chapters 5 to 9 covering the
remaining phases Define, Design, and Refine as well as additional topics.
Foundations: API Visibility and Integration Types 137

Foundations: API Visibility and Integration Types


The patterns presented in this section are rather simplistic terms of design forces and
their resolution, but they serve as building blocks for the subsequent, more advanced
patterns. Therefore, we present them here in a simplified form: Context and Prob-
lem, Solution, and Details. Feel free to proceed to Chapter 5, “Define Endpoint
Types and Operations,” and return here as needed.
The foundation patterns deal with the two strategic decisions:

• Which types of systems, subsystems, and components are integrated?


• From where should an API be accessible?

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.

API visibility alternatives

document visible aspects


of the API contract

Public API Community API Solution-Internal


API

combine integration type with


selected visibility option
API Description

alternative integration types

codify integration
Frontend Backend aspects of the API
Integration Integration

Figure 4.4 Pattern map for foundation patterns


138 Chapter 4 Pattern Language Introduction

Note that the API Description pattern is covered in Chapter 9.

Pattern:
frontEnd intEgration

In Chapter 1, we motivated the emergence of mobile apps and cloud-native applica-


tions as one reason why APIs matter so much. They provide mobile apps and Web
clients of cloud applications with data and access to provider-side processing
capabilities.

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

In Chapter 1, we discussed that cloud-native applications and microservices-based


systems require APIs to both connect and separate their parts. APIs also play a key
role in software ecosystems. More generally speaking, any backend system may
benefit from and rely on remote APIs when requiring information from or desiring
activity in other systems.

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

User Interface User Interface

Backend
Integration

Business Logic API Business Logic

Data Persistence Data Persistence

Figure 4.6 BACKEND INTEGRATION sketch 1: System-to-system message exchange

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

End-User Interface and External Gateways

Business Logic Business Logic


Service 1 API Service 2

Backend
Integration
Data Persistence Data Persistence

Figure 4.7 BACKEND INTEGRATION sketch 2: Microservices communicating via SOLUTION-


INTERNAL API

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.

How can an API be made available to an unlimited and/or unknown num-


ber of API clients outside the organization that are globally, nationally, and/or
regionally distributed?
Expose the API on the public Internet along with a detailed API Description
that describes both functional and nonfunctional properties of the API.

Figure 4.8 sketches the Public API pattern in an exemplary scenario.

Application Frontend, Application Backend


Other Systems
(Internet)
End Users
Backend Database
Public
Web App
API

Mobile App

Third-Party
Systems

Figure 4.8 API visibilities: PUBLIC API in context

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.

Application Frontend Application Backend


(Extranet)

End Users
(Extranet)
Web App

Community
API
Tenant Ops
Mobile App

Business Logic

Database

Figure 4.9 API visibilities: COMMUNITY API in context

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

Some APIs structure applications into components, for instance, services/microser-


vices or program-internal modules. In such cases, API clients and their providers often
run in the same data center or even on the same physical or virtual compute node.

How can access to and usage of an API be limited to an application, for


instance, components in the same or another logical layer and/or physical tier?
Decompose the application logically into components. Let these components
expose local or remote APIs. Offer these APIs only to system-internal commu-
nication partners such as other services in the application backend.

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

Application Frontend Application Backend


(Intranet)

End Users Business Logic 1

Web App

Solution-Internal Solution-Internal
Frontend API Backend API

Mobile App

Business Logic 2

Database

Figure 4.10 API visibilities: SOLUTION-INTERNAL API

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.

Foundation Patterns Summary


This concludes our coverage of five foundation patterns in this chapter. Chapter 3
features these patterns as decisions required and problem-solution pairs.
Note that Frontend Integration is sometimes called vertical integration, while
Backend Integration is called horizontal integration. The notion originates from a
146 Chapter 4 Pattern Language Introduction

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.

Basic Structure Patterns


API contracts describe the unique address of one or more API endpoints (such as an
HTTP resource URI), their operations (such as supported HTTP verbs or the name
of a SOAP Web service operation), plus the structures of the request and response
messages of each operation. The data structures defining these messages are an
essential part of the API contract; the domain model in Chapter 1 features them as
representation elements. Figure 4.1 presented exemplary request and response mes-
sages at the start of this chapter.
Design questions about these data structures (representation elements) arise:

• What is an adequate number of representation elements for request and


response messages?
• How should these elements be structured and grouped?
Basic Structure Patterns 147

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.

Have roles (element stereotypes) and base data types

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

Parameter Tree Parameter Forest

Appear in request and response messages

Figure 4.11 Patterns to structure messages and their representation elements


148 Chapter 4 Pattern Language Introduction

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).

How can simple, unstructured data (such as a number, a string, a Boolean


value, or a block of binary data) be exchanged between API client and API
provider?
Define a single parameter or body element. Pick a basic type from the type
system of the chosen message exchange format for it. If justified by receiv-
er-side usage, identify this Atomic Parameter with a name. Document name
(if present), type, cardinality, and optionality in the API Description.

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.

Request Message of API Call

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>

The notation of this example is Microservice Domain-Specific Language (MDSL;


see Appendix C for an introduction). In the API of the Customer Core application
at Lakeside Mutual, such parameters can be used to retrieve the city of a customer:

curl -X GET --header 'Authorization: Bearer b318ad736c6c844b' \


http://localhost:8110/customers/gktlipwhjr?fields=city
{
"customers": [{
"city": "St. Gallen",
"_links": {
"self": {
"href": "/customers/gktlipwhjr?fields=city"
},
"address.change": {
"href": "/customers/gktlipwhjr/address"
}
}
}],
...
}

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>*

A JSON instance of the preceding definition is

{ "streetAddress": [ "sampleStreetName1", "sampleStreetName2"]}

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.

How can multiple related Atomic Parameters be combined in a representa-


tion element so that each of them stays simple, but their relatedness becomes
explicit in the API Description and the runtime message exchanges?
Group two or more simple, unstructured data elements in a single cohesive
representation element to define an Atomic Parameter List that contains
multiple Atomic Parameters. Identify its items by position (index) or by a
string-valued key. Identify the Atomic Parameter List as a whole with its own
name as well if that is needed to process it in the receiver. Specify how many
elements are required and permitted to appear.
Basic Structure Patterns 151

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.

Request Message of API Call

Data Transfer Representation

Param. Param. Param.


"ABC" 42 true

Figure 4.13 ATOMIC PARAMETER LIST pattern: Grouped atoms

In the Lakeside Mutual case, an Atomic Parameter List may represent customer
addresses (MDSL notation):

data type AddressRecord (


"streetAddress":D<string>*,
"postalCode":D<int>?,
"city":D<string>
)

The streetAddress is set-valued, indicated by the asterisk *. The postalCode


is marked as optional in this example, indicated by the question mark ?.
A JSON representation of sample data adhering to this definition is

{
"street": ["sampleStreetName"],
"postalCode": "42",
"city": "sampleCityName"
}

Revisiting the Customer Core example from the Atomic Parameter, it


might be required to specify multiple fields in the request. In that case, a single
fields=city,postalCode parameter, which is an Atomic Parameter List,
152 Chapter 4 Pattern Language Introduction

allows the API client to indicate that it wants the provider to include certain (but not
all) fields in the response:

curl -X GET --header 'Authorization: Bearer b318ad736c6c844b' \


http://localhost:8110/customers/gktlipwhjr?\
fields=city,postalCode

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).

How can containment relationships be expressed when defining complex rep-


resentation elements and exchanging such related elements at runtime?
Define a Parameter Tree as a hierarchical structure with a dedicated root
node that has one or more child nodes. Each child node may be a single
Atomic Parameter, an Atomic Parameter List, or another Parameter
Tree, identified locally by a name and/or by position. Each node might have
an exactly-one cardinality but also a zero-or-one cardinality, an at-least-one
cardinality, or a zero-or-more cardinality.
Basic Structure Patterns 153

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.

Request Message Response Message


Data Transfer Data Transfer
Representation (In) Representation (Out)

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):

data type MoveHistory {


"from":AddressRecord, "to":AddressRecord, "when":D<string>
}
data type CustomerWithAddressAndMoveHistory {
"customerId":ID<int>,
"addressRecords":AddressRecord+, // one or more
"moveHistory":MoveHistory* // type reference, collection
}

This MDSL data definition CustomerWithAddressAndMoveHistory might


produce the following JSON object-array structure at runtime:

{
"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"
}]
}

The MDSL Web site6 provides more examples.

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.

How can multiple Parameter Trees be exposed as a request or response pay-


load of an API operation?
Define a Parameter Forest comprising two or more Parameter Trees.
Locate the forest members by position or name.

Figure 4.15 illustrates the pattern.

Request Message
Data Transfer Representation

Figure 4.15 PARAMETER FOREST pattern

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.

data type CustomerProductForest [


"customers": { "customer":CustomerWithAddressAndMoveHistory }*,
"products": { "product":ID<string> }
]
156 Chapter 4 Pattern Language Introduction

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:

public interface CustomerInformationHolder {


boolean uploadSingleParameter(
CustomerProductForest newData);
boolean uploadMultipleParameters(
List<Customer> newCustomer, List<String> newProducts);
}

The uploadSingleParameter method uses a single class CustomerProduct-


Forest as its input (containing customer and product trees), while uploadMul-
tipleParameters works with two parameters, of type List<Customer> and
List<String>. Note that the latter can easily be refactored into the former.

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

A Parameter Forest can be turned into a Parameter Tree by introducing an


“artificial” root node; similarly, Atomic Parameter Lists and flat Parameter Trees
are equivalent. Therefore, recursive Parameter Trees and Atomic Parameter as
leaf nodes would suffice to represent arbitrarily complex data structures. One might
wonder about the merit of having four distinct patterns rather than two. We decided
to present four design options as patterns to be able to model the intricacies of vari-
ous technologies such as HTTP, WSDL/SOAP, gRPC, and so on—without hiding
their conceptual differences and without losing generality.

Basic Structure Patterns Summary


The data part of the API contract, established by the structures of request and
response message payload, directly contributes to (or harms) the developer experi-
ence. Qualities such as interoperability and maintainability are at stake. Chapter 1
provides a deeper discussion of these and many more desired qualities (and related
design challenges).
The use of the patterns results in platform-independent schema definitions that
correspond to JSON schema (as used in OpenAPI), Protocol Buffer specifications, or
GraphQL Schema Language (see Table 4.2).

Table 4.2 Basic Structure Patterns and Their Known Uses


XML, XML Protocol
Theme Pattern JSON Schema Buffers GraphQL
Plain data Atomic Basic/primitive Simple types Scalar value Scalar types
Parameter types types
(single-valued)
Map/ Atomic Object {...}, Sequence of size 1, Nested types input
record Parameter not including referencing built-in and type
List other objects or custom types definitions
Nesting Parameter Object including Complex types Message input
Tree other objects referencing and type
{...{...}...} other messages definitions
referencing
others
Group Parameter Top-level array Can be modeled n/a n/a
of nested Forest of objects in WSDL (but not
elements used in practice)
Collection Variant of other Array [...] maxOccurs= repeated flag Array [...]
patterns (atoms, "unbounded"
trees)
158 Chapter 4 Pattern Language Introduction

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

Define Endpoint Types and


Operations

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

Introduction to API Roles and Responsibilities


Business-level ideation activities often produce collections of candidate API end-
points. Such initial, tentative design artifacts typically start from API design goals
expressed as user stories (of various forms), event storming output, or collaboration
scenarios [Zimmermann 2021b]. When the API realization starts, these interface
candidates have to be defined in more detail. API designers seek an appropriate bal-
ance between architectural concerns such as granularity of the services exposed by
the API (small and specific vs. large and universal) and degree of coupling between
clients and API provider implementations (as low as possible, as high as needed).
The requirements for API design are diverse. As explained previously, goals derived
from the business-level activities are a primary source of input, but not the only one;
for instance, external governance rules and constraints imposed by existing backend
systems have to be taken into account as well. Consequently, the architectural roles of
APIs in applications and service ecosystems differ widely. Sometimes, API clients just
want to inform the provider about an incident or hand over some data; sometimes,
they look for provider-side data to continue their processing. When responding to
client requests, providers may simply return a data element already available—or
may perform rather complex processing steps (including calls to other APIs). Some
of the provider-side processing, whether simple or complex, may change the provider
state, some might leave this state untouched. Calls to API operations may or may
not be part of complex interaction scenarios and conversations. For instance, long-
running business processes such as online shopping and insurance claims manage-
ment involve complex interactions between multiple parties.
The granularity of the operations varies greatly. Small API operations are easy to
write, but there might be many, which have to be composed with their invocations
being coordinated over time; few large API operations may be self-contained and
autonomous, but they can be difficult to configure, test, and evolve. The runtime
operations management of many small units also differs from that of a few big ones;
there is a flexibility versus efficiency trade-off.
API designers have to decide how to give operations a business meaning (this, for
instance, is a principle in service-oriented architectures [Zimmermann 2017]). They
also have to decide if and how to manage state; an operation might simply return
a calculated response but might also have a permanent mutational effect on the
provider-side data stores.
In response to these challenges, the patterns in this chapter deal with endpoint and
operation semantics in API design and usage. They carve out the architectural role of
API endpoints (emphasis on data or activity?) and the responsibilities of operations
(read and/or write behavior?).
Introduction to API Roles and Responsibilities 163

Challenges and Desired Qualities


The design of endpoints and operations, expressed in the API contract, directly influ-
ences the developer experience in terms of function, stability, ease of use, and clarity.

• Accuracy: Calling an API rather than implementing its features oneself


requires a certain amount of trust that the called operation will deliver correct
results reliably; in this context, accuracy means the functional correctness of
the API implementation with regard to its contract. Such accuracy certainly
helps building trust. Mission-critical functionality deserves particular atten-
tion. The more important the correct functioning of a business process and its
activities is, the more effort should be spent on their design, development, and
operations. Preconditions, invariants, and postconditions of operations in the
API contract communicate what clients and providers expect from each other
in terms of request and response message content.
• Distribution of control and autonomy: The more work is distributed, the more
parallel processing and specialization become possible. However, distribution of
responsibilities and shared ownership of business process instances require coor-
dination and consensus between API client and provider; integrity guarantees
have to be defined, and consistent activity termination must be designed. The
smaller and more autonomous an endpoint is, the easier it becomes to rewrite it;
however, many small units often have a lot of dependencies among each other,
making an isolated rewrite activity risky; think about the specification of pre-
and postconditions, end-to-end testing, and compliance management.
• Scalability, performance, and availability: Mission-critical APIs and their
operations typically have demanding Service Level Agreements that go
along with the API Description. Two examples of mission-critical compo-
nents are day trading algorithms at a stock exchange and order processing and
billing in an online shop. A 24/7 availability requirement is an example of a
highly demanding, often unrealistic quality target. Business processes with
many concurrent instances, implemented in a distributed fashion involving
a large number of API clients and involving multiple calls to operations, can
only be as good as their weakest component in this regard. API clients expect
the response times for their operations calls to stay in the same order of mag-
nitude when the number of clients and requests increases. Otherwise, they will
start to question the reliability of the API.
Assessing the consequences of failure or unavailability is an analysis and
design task in software engineering but also a business leadership and risk
management activity. An API design exposing business processes and their
164 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].

Patterns in this Chapter


Resolving the preceding design challenges is a complex undertaking; many design
tactics and patterns exist. Many of those have already been published (for instance,
Introduction to API Roles and Responsibilities 165

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?

The output produced by API implementations when processing calls to opera-


tions also requires attention:

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:

• The pattern Processing Resource can help to realize activity-oriented API


endpoints.
• Data-oriented API endpoints are represented by Information Holder
Resources.

The section “Endpoint Roles” covers Processing Resource and Information


Holder Resource. Specialized types of Information Holder Resources exist.
For instance, Data Transfer Resource supports integration-oriented APIs, and
Link Lookup Resource has a directory role. Operational Data Holders, Master
Data Holders, and Reference Data Holders differ concerning the characteristics
of data they expose in terms of data lifetime, relatedness, and mutability.
The four operation responsibilities found in these types of endpoints are Compu-
tation Function, Retrieval Operation, State Creation Operation, and State
Transition Operation. These types are covered in the section “Operation Respon-
sibilities.” They differ in terms of client commitment (preconditions in API contract)
166 Chapter 5 Define Endpoint Types and Operations

and expectation (postconditions), as well as their impact on provider-side applica-


tion state and processing complexity.
Figure 5.1 summarizes the patterns in this chapter.

Infrastructure for data


(endpoint-level)
Link Lookup
Resource

Data
Transfer
Resource

Inheritance: Different types of data (life-


time, referencing, change dynamics)
Functional vs. data perspective
(endpoint-level)
Realization strategy

Processing Information
Resource Holder
Resource

State Write Life Span


no yes Short living Long living

?
Stored data characteristics
Responsibilities & constraints

A A’
(endpoint-level)
Mutable by Client
(operation-level)

Computation State Creation Operational Master Data


yes
State Read

Function Operation Data Holder Holder


yes no

no

A A’

Retrieval State Transition Reference Data


Operation Operation Holder

Figure 5.1 Pattern map for this chapter (endpoint roles and operations responsibilities)
Endpoint Roles (aka Service Granularity) 167

Endpoint Roles (aka Service Granularity)


Refining the pattern map for this chapter, Figure 5.2 shows the patterns representing
two general endpoint roles and five types of information holders.

Endpoint Roles

Processing Resource Information Holder Resource

+ stateCreationOperation() + createInformationHolder()
+ retrievalOperation() + getInformationHolder()
+ stateTransitionOperation() + updateInformationHolder()
+ computationFunction() + deleteInformationHolder()
+ searchInformationHolder()

Information Holder Types

Operational Master Data Reference Data Link Lookup Data Transfer


Data Holder Holder Holder Resource Resource

Figure 5.2 Patterns distinguishing endpoint roles

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?

Let us cover Processing Resource first, followed by Information Holder


Resource and its five specializations.
168 Chapter 5 Define Endpoint Types and Operations

Pattern:
ProCEssing rEsourCE

When and Why to Apply


The functional requirements for an application have been specified, for instance, in
the form of user stories, use cases, and/or analysis-level business process models. An
analysis of the functional requirements suggests that something has to be computed
or a certain activity is required. This cannot or should not be done locally; remote
Frontend Integration and/or Backend Integration APIs are required. A prelimi-
nary list of candidate API endpoints might have been collected already.

How can an API provider allow its remote clients to trigger actions in it?

Such actions may be short-lived, standalone commands and computations


(application-domain-specific ones or technical utilities) or long-running activities in
a business process; they may or may not read and write provider-side state.

We can ask more specifically:

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:

• Contract expressiveness and service granularity (and their impact on cou-


pling): Ambiguities in the invocation semantics harm interoperability and can
lead to invalid processing results (which in turn might cause bad decisions to
be made and consequently other harm). Hence, the meaning and side effects of
the invoked action (such as a self-contained command or part of a conversa-
tion), including the representations of the exchanged messages, must be made
clear in the API Description. The API Description must be clear in what end-
points and operations do and do not do; preconditions, invariants, and post-
conditions should be specified. State changes, idempotence, transactionality,
event emission, and resource consumption in the API implementation should
Endpoint Roles (aka Service Granularity) 169

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

Add a Processing Resource endpoint to the API exposing operations that


bundle and wrap application-level activities or commands.
Endpoint Roles (aka Service Granularity) 171

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

UtilityFunctions Database Backend Adapter


Adapter

Process Instance Data Store


Processing Backend

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) {

The Lakeside Mutual application services also contain RiskComputation-


Service, a stateless Processing Resource that implements a single Computation
Function called computeRiskFactor:

@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) {

int age = getAge(riskFactorRequest.getBirthday());


String postalCode = riskFactorRequest.getPostalCode();
int riskFactor = computeRiskFactor(age, postalCode);
return ResponseEntity.ok(
new RiskFactorResponseDto(riskFactor));
}

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-