“All architecture is design, but not all design is architecture. Architecture represents the set of significant design decisions that shape the form and the function of a system.”
Grady Booch
Organizations have been delivering APIs for decades. APIs started as libraries and components shared across an organization and sold by third parties. They then grew into distributed components using standards such as CORBA for distributed object integration and SOAP for integrating distributed services across organizations. These standards were designed for interoperability but lacked the elements of effective design, often requiring months of effort to successfully integrate them.
As these standards were replaced by web APIs, only a few APIs were needed. Teams could take the time to properly design them, iterating as needed. This is no longer the case. Organizations deliver more APIs and at greater velocity than ever before. The reach of web APIs goes beyond a few internal systems and partners.
Today’s web-based APIs connect organizations to their customers, partners, and workforce using the standards of the web. Hundreds of libraries and frameworks exist to make it cheap and fast to deliver APIs to a marketplace or for internal use. Continuous integration and delivery (CI/CD) tools make it easier than ever to build automation pipelines to ensure APIs are delivered with speed and efficiency.
Yet, the biggest challenge for today’s API programs continues to be successfully designing APIs that can be understood and integrated by developers in a consistent and scalable fashion. Facing this challenge requires organizations to recognize that web APIs are more than just technology. Just as works of art require the balance of color and light, API design benefits from the blending of business capabilities, product thinking, and a focus on developer experience.
An organization’s collection of APIs provides a view into what the business values in the marketplace. The design quality of its APIs provides a view into how the business values developers. Everything an API offers−and doesn’t offer−speaks volumes about what an organization cares most about. Effective web API design incorporates three important elements: business capabilities, product thinking, and developer experience.
Business capabilities describe the enablers an organization brings to market. This may include external-facing capabilities, such as unique product design, amazing customer service, or optimized product delivery. It may also include internally facing capabilities such as sales pipeline management or credit risk assessment.
Organizations deliver business capabilities in three ways: directly by the organization, outsourced via a third-party provider, or through a combination of organizational and third-party processes.
For example, a local coffee shop may choose to sell custom coffee blends. To do so, they source coffee beans through a third-party distributor, roast the coffee beans themselves, then utilize a third-party point-of-sale system (POS) for selling their coffee blends in a retail store. By outsourcing some of the necessary business capabilities to specialized third parties, they are able to focus on delivering specific business capabilities that differentiate them from others in the marketplace.
APIs digitize the business capabilities that an organization brings to a marketplace. When embarking on designing a new API or expanding an existing API, the underlying business capabilities should be well understood and reflected into the API design.
Organizations were integrating with partners and customers prior to the growth of web APIs. The challenge most organizations face, however, is that each integration has been custom-made. For each new partner or customer integration, a dedicated team consisting of developers, a project manager, and an account manager were tasked with building a custom integration. This involved tremendous effort and was often repeated, with per-partner customizations.
The growth of the software-as-a-service (SaaS) business model, along with the increase in demand for web APIs, have shifted the discussion from one-off integration with partners and customers to a focus on product thinking.
Applying product thinking to the API design process shifts the team focus from a single customer or partner to an effective API design that is able to handle new automation opportunities with little-to-no customization effort for a given customer segment. It also enables a self-service model for workforce, business-to-business, and customer-driven integration.
The focus of an API product becomes less on custom implementations and more on meeting market needs in a scalable and cost-effective way. Reusable APIs emerge from considering multiple consumers at once. When embarking on the design of a new API, use a product thinking approach to obtain feedback from multiple parties that will consume the API. This will shape the API design early and lead to increased opportunities for reuse.
User experience (UX) is the discipline of meeting the exact needs of the user, from their interactions with the company, its services, and the product itself. Developer experience (DX) is just as important for APIs as UX is for products and services. The developer experience focuses on the various aspects of engagement with developers for an API product. This extends beyond the operational details of the API. It also includes all aspects of the API product, from first impressions to day-to-day usage and support.
A great developer experience is essential to the success of an API. When a great DX is delivered, developers quickly and confidently consume a web API. It also improves the market traction of productized APIs by moving developers from being integrators to becoming experts on the API. The expertise translates directly into the ability to deliver real value to their customers and their business quickly and with reduced effort.
As API teams seek to understand how to design a great experience for their API, remember that DX is an important factor for internal developers, also. For example, great documentation enables internal developers to understand and consume an API quickly, whereas an API that has poor documentation requires contacting the internal team responsible for the API to learn how to use it properly. While they may be able to gain direct access to the developers that designed and implemented an API, it adds unnecessary communication overhead. Internal developers benefit from great DX because they can create business value faster.
Case Study: APIs and Product Thinking Meets Banking
Capital One started their API journey in 2013 with the goal of developing an enterprise API platform. The initial set of platform APIs focused on delivering automation throughout the organization to increase velocity of delivery while breaking down siloed barriers.
As the number of digital capabilities in their API platform grew, their focus shifted from internal APIs to several product opportunities in the marketplace. They launched their public-facing developer portal called DevExchange at South By Southwest (SXSW) with several API products. These product offerings included bank-grade authorization, a rewards program, credit card pre-qualification, and even an API to create new savings accounts.
They extended the idea further by leveraging their digital capabilities to develop an omnichannel presence. APIs used to power their website and mobile app were used as a foundation for a voice-based interactive experience using Amazon’s Alexa platform and interactive chat using a chatbot named Eno (the word “one” spelled backwards).
Taking a product-based approach to their APIs, along with a robust API portfolio of digital capabilities, allowed them to explore opportunities with their customers and partners. It didn’t happen overnight, but it did happen because of an API focus that started with an executive vision and execution by the entire organization.
When developers think of software design, thoughts of classes, methods, functions, modules, and databases likely spring to mind. UML sequence and activity diagrams, or simple box and arrow diagrams if preferred, are used to convey understanding across a code base. All these elements are part of the communication process development teams use for understanding and future developer onboarding.
Likewise, API design is a communication process. Rather than communicating inwardly between the members of a single team, APIs shift the communication outward. The lines of communication are extended in three distinct ways:
■ Communication across network boundaries: An API’s design, including its choice of protocol, has an impact on the chattiness of the API. Network protocols, such as HTTP, are better for coarse-grained communication. Other protocols such as MQTT and AMQP, often used for messaging APIs, are better suited for fine-grained communication within a defined network boundary. The API design reflects the frequency of communication between systems and the impact it may have on performance due to network boundaries and bottlenecks. The API design process has a heavy impact on performance of the client and server.
■ Communication with consuming developers: API design and associated documentation are the user interface for developers. It informs developers how and when they are able to use each API operation. It will also determine if and how they are able to combine operations to achieve more complex results. Communication early and often during the API design process is essential to meet the needs of developers consuming the API.
■ Communication to the marketplace: API design and documentation informs prospective customers, partners, and internal developers what outcomes the APIs make possible through the digital capabilities they offer. Effective API design helps to communicate and enable these digital capabilities.
API design is an important part of communication. An API design process helps us to consider these aspects of communication during the design phase.
Software design focuses on the organization and communication of software components within a code base. Techniques such as code comments, sequence diagrams, and the judicious use of design patterns help improve the communication effort between team members.
Web API design builds upon these principles of software design, but with a broader audience that extends beyond the team or organization. The scope of communication expands beyond a single team or organization to developers all over the world. Yet, the same principles of software design apply to web-based API design: modularization, encapsulation, loose coupling, and high cohesion. While these may be subjects familiar to most developers, they are fundamental to API design and need review before approaching any API design process.
Modules are the smallest atomic unit within a software program. They are composed of one or more source files that contain classes, methods, or functions. Modules have a local, public API to expose the functionality and business capabilities that they offer to other modules within the same codebase. Modules are sometimes referred to as components or code libraries.
Most programming languages support modules through the use of namespaces or packages that group code together. Grouping related code that collaborates together into the same namespace encourages high cohesion. Internal details of a module are protected through access modifiers provided by the programming language. For example, the Java programming language has keywords such as public
, protected
, package
, and private
that help to encourage loose coupling through limited exposure of a module.
As more and more modules are combined, a software system is created. A subsystem combines modules into a larger module in more complex solutions, as shown in Figure 1.1.
Figure 1.1 Modules combine into larger and larger units, resulting in a software system
Applying the same concepts of modularization to web-based API design helps to find the boundaries and responsibilities of every API. This will ensure clear responsibilities across complementary APIs that focus on externalizing digital capabilities while hiding the internal implementation details. Consuming developers benefit by understanding the API quickly and effectively.
Encapsulation seeks to hide the internal details of a component. Scope modifiers are used to limit access to a module’s code. A module exposes a set of public methods or functions, while hiding the internal details of the module. Internal changes may occur without impacting other modules that depend upon its public methods. Sometimes this is referred to as information hiding, a concept applied to software development since the 1970s by David Parnas.
Web APIs extend this concept a bit further. They hide the internal details of programming language, choice of web framework, the classes and objects of a system, and database design behind an HTTP-based API. Internal details, encapsulated behind the API design, encourage a loosely coupled API design that depends upon messages rather than underlying database design and models for communication. No longer does an organization need to understand all the internal implementations details, such as for a payment gateway. Instead, they only need to understand the operations that the API offers and how to use them to achieve the desired outcomes.
High cohesion is a term used when the code within a module is all closely related to the same functionality. A highly cohesive module results in less “spaghetti code,” as method calls aren’t jumping all over the codebase. When code is scattered across the entire codebase, calls frequently jump across modules and back again. This style of code is considered to exhibit low cohesion.
Coupling is the degree of interdependence between two or more components. Tightly coupled components indicates that the components are very constrained by the implementation details of the other. Loosely coupled components hide the components’ internal details away from others, restricting the knowledge between modules to a public interface, or programming language API, that other areas of the code can invoke.
Figure 1.2 demonstrates the concepts of high cohesion and loose coupling within and across modules.
Figure 1.2 Loose coupling and high cohesion are fundamentals of modular API design
Web APIs extend these concepts by grouping related API operations together for high cohesion, while ensuring that the internal details are encapsulated to encourage a loosely coupled API design.
A resource is a digital representation of a concept, often an entity or collection of entities that may change over time. It consists of a unique name or identifier that can reference documents, images, collections of other resources, or a digital representation of anything in the real world such as a person or thing. Resources may even represent business processes and workflows.
Resource-based APIs focus on interactions across a network, independent of how they are stored in a database or manifested as objects. They offer different operations, or affordances, as possible interactions with a specific resource. Additionally, resources support multiple representations that allow a web app, mobile app, and reporting tool to interact with the resource using different media formats such as JSON or XML.
It is important to recognize that resources are not the same thing as a data model that resides with a database. The data model, often reflected as a schema design in a database, is optimized for the read and write interactions necessary to support the required I/O performance and reporting needs of a solution.
While data may be part of an API, the data model should not be used as the basis of API design. Data models meet a specific set of requirements, including read and write performance, optimized data storage, and optimized query support. Data models are optimized for the internal details of an application.
Like the choice of programming languages and frameworks, the choice of database types and vendors change over time. APIs designed to directly map to a data or object model expose these internal implementation details to API consumers. The result is a more fragile API must introduce significant design changes when the data model changes.
Web API design seeks to achieve a different set of goals, including delivering outcomes and experiences, optimized network access, and programming language independence. Because APIs involve integration between systems, they should remain stable over a long period of time, whereas data models may change to accommodate new or changing data access requirements.
Like most technology choices, preferences in the type of database change with time. Relational databases are still heavily used, but additional choices including document and columnar databases have gained recent popularity. While APIs may have an impact on the data model, an API design should evolve independently from the latest database trends.
What happens when teams expose a data model as an API?
Constant code changes: Database schema changes will result in a constantly changing API, as the API must keep in lockstep with the underlying database. This change to the data model will force consumers into a complex conformist relationship in which they must rewrite their API integration code every time the underlying data model changes. This may be overcome by an anti-corruption layer that isolates a unit of code from these changes. However, the constant flux of the API creates a high cost of development as downstream developers maintain the anti-corruption layer.
Create network chattiness: Exposing link tables as separate API endpoints will cause API “chattiness” as the consumer is forced to make multiple API calls, one for each table. This is similar to how an n+1 query problem degrades database performance. While an n+1 problem can be a performance bottleneck for databases, API chattiness will have a devastating impact on API performance.
Data inconsistencies: Not only will performance suffer from network chattiness, but the n+1 problem will also result in data inconsistencies. Clients will be forced to make multiple API calls and stitch the results together into a single unified view. This may result in incomplete or corrupted data due to inconsistent reads, perhaps across transactional boundaries, that occur from multiple API requests necessary to obtain necessary data.
Confuse API details: Columns optimized for query performance, such as a CHAR(1)
column that uses character codes to indicate status, become meaningless to API consumers without additional clarification.
Expose sensitive data: Tools that build APIs that mirror a data model expose all columns with a table using SELECT * FROM [table name]
. This also exposes data that API consumers should never see, such as personally identifiable information (PII). It may also expose data that helps hackers compromise systems through a better understanding of the internal details of the API.
API resources are not the same as objects in an object-oriented code base. Objects support collaboration within a codebase. Objects are often used to map data models into code for easier manipulation. They suffer from the same issues as exposed data models: constant code changes, network chattiness, and data inconsistencies.
Likewise, domain models, typically comprised of objects, represent the specific business domain. They may be used in a variety of ways to address the needs of the system. They may even traverse different transactional contexts based upon how they are applied. Web APIs, however, are most effective when they take transactional boundaries into consideration. In this case, web APIs are more akin to aggregates than domain or object models.
Keep in mind that API consumers don’t have the luxury of seeing the details of a data model and all the code behind an API. They didn’t sit in on the endless meetings that resulted in the multitude of decisions that drove a data model design. They don’t have the context of why data model design decisions were made. Great API designs avoid leaking internal details, including database design choices, by shifting from data design to message design.
Resource-based APIs create a conversation between the business and a user or remote system. For example, suppose a user of a project management application was conversing with the API server. The conversation may look something like what’s shown in Figure 1.3.
Figure 1.3 An example interaction between an API client and API server, as if the user was talking to the server in conversational terms.
Does it seem strange to think about APIs as a chat session? It isn’t far off from what Alan Kay originally intended when he coined the term object-oriented programming. Rather than a focus on inheritance and polymorphic design, he envisioned object-oriented programming as sending messages between components:
“I'm sorry that I long ago coined the term objects for this topic because it gets many people to focus on the lesser idea. The big idea is messaging.” − Alan Kay, 1998
Like Alan Kay’s original vision for object-oriented programming, web APIs are message-based. They send request messages to a server and receive a response message as a result. Most web APIs perform this message exchange synchronously by sending a request and waiting for the response.
API design considers the conversational message exchange between systems to produce desired outcomes by customers, partners, and the workforce. A great API design also considers how this communication evolves as requirements change.
An API design approach must include a balance between robust digital capabilities and a focus on a great developer experience that supports quick and easy integration. It must be rooted in a series of principles that create a solid foundation. These five principles establish the necessary foundation and are detailed throughout this book:
■ Principle #1: APIs should never be designed in isolation. Collaborative API design is essential for a great API. (Chapter 2)
■ Principle #2: API design starts with an outcome-based focus. A focus on the outcome ensures the API delivers value to everyone. (Chapters 3-6)
■ Principle #3: Select the API design elements that matches the need. Trying to find the perfect API style is a fruitless endeavor. Instead, seek to understand and apply the API elements appropriate for the need, whether that is REST, GraphQL, gRPC, or an emerging style just entering the industry. (Chapters 7-12)
■ Principle #4: API documentation is the most important user interface for developers. Therefore, API documentation should be first class and not left as a last-minute task. (Chapter 13)
■ Principle #5: APIs are forever, so plan accordingly. Thoughtful API design combined with an evolutionary design approach makes APIs resilient to change. (Chapter 14)
Web API design incorporates three important elements to deliver a successful API: business capabilities, product thinking, and developer experience. These cross-functional disciplines mean that organizations cannot ignore the process of API design. Developers, architects, domain experts, and product managers must work together to design APIs that meet the needs of the marketplace.
Additionally, web API design builds upon the principles of software design, including modularization, encapsulation, loose coupling, and high cohesion. API designs should hide the internal details of the systems they externalize. They should not expose underlying data models, but rather focus on a system-to-system message exchange that is both flexible in design and resilient to change over time.
So, how do teams go from business requirements to an API design that is evolvable, while delivering the desired outcomes to customers, partners, and the internal workforce? That is the subject of the next chapter, which introduces a process that bridges business and product requirements into an API design. The process is explored in detail in subsequent chapters.