API Design Principles
The purpose of this document is to provide guidance on a number of principles and design heuristics that software developers and architects should consider when designing APIs. All recommendations have been grouped into to one of three "Maturity Levels".
- Basic: The most fundamental API design principles
- Intermediate: These principles encourage designers to create APIs that are easy to use and consistent across (business) problem domains.
- Advanced: These principles focus on increased levels of usability and maintainability
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 .
API designers SHOULD leverage industry accepted standards (i.e. Request For Comments (RFCs)) as much as possible rather than create proprietary approaches.
As an example, API designers SHOULD use HTTP status codes the way they were intended. HTTP status codes should not be repurposed, nor should new codes be invented or introduced. HTTP is a complete Application Protocol, and the only way to ensure reliable communications between networked systems when using HTTP is to abide by the basic rules it prescribes.
Here are the core RFCs for HTTP Status Codes:
- RFC 2616, Section 10 Status Code Definitions
- RFC 6585, Additional HTTP Status Codes
- IANA HTTP Status Code Registry
Design by Contract (DbC)
APIs are defined by formal and explicit Interface specifications or "Contracts" that stand apart from the "Service Implementation". These Service Descriptors identify the logical operations or resources a client may use, their inputs and outputs, as well as their Pre-Conditions and Post-Conditions. Such Contracts should enable client developers and non-engineering personnel to understand the capabilities of a service, and how to use them.
Contracts MUST be described through a formal Service Descriptor language (e.g. Swagger, Open API Specification). While API contracts described with Service Descriptor languages may be produced through a "Contract-First" (i.e. the Descriptor is created first, then the code is generated from the Descriptor) or a "Code-First" approach (i.e. the code is created first, and Descriptors are generated from the code, either at build-time or run-time), the "Contract-First" approach is better aligned with the Design by Contract (DbC) philosophy because it encourages us to focus on the service Interface and client interactions first rather than the service's implementation.