What Makes a Good API? Principles and Best Practices for Robust Design
This article explores the challenges of API design, outlines fundamental principles such as clear mental models, simplicity, multiple implementations, and idempotency, and provides concrete best‑practice recommendations illustrated with the classic POSIX File API example.
Introduction
APIs are the core of software systems, and their design directly impacts system complexity, maintainability, and evolution. Good API design helps developers understand, debug, test, extend, and maintain systems effectively.
Scope
The focus is on general API design for remote calls (RPC or HTTP/RESTful), not on REST‑specific issues. It assumes clients interact directly with remote services, though in Alibaba many clients use SDKs as proxies.
Fundamental API Design Principles
Provide a Clear Mental Model
A good API conveys a consistent mental model to designers, maintainers, and users, reducing misunderstandings.
Keep It Simple
Design should avoid unnecessary complexity while not oversimplifying to the point of losing essential semantics.
Allow Multiple Implementations
An API that can be implemented in completely different ways demonstrates a strong abstraction and reduces tight coupling.
QueryOrderResponse queryOrder(string orderQuery)Adding a useCache flag may leak backend details, illustrating the risk of exposing implementation specifics.
Best‑Practice Recommendations
Study Proven Examples
The POSIX File API exemplifies a successful design: stable for decades, clear concepts, and supports many underlying file system implementations.
int open(const char *path, int oflag, ...);
int close(int filedes);
int remove(const char *fname);
ssize_t write(int fildes, const void *buf, size_t nbyte);
ssize_t read(int fildes, void *buf, size_t nbyte);Document Thoroughly
Maintain up‑to‑date documentation for every field and method to reduce client errors and improve development efficiency.
Define Resources Carefully
Choose appropriate abstractions (e.g., file, data block) and decide whether identifiers should be free‑form strings or structured data.
{
"disk": "string",
"path": "string"
}Identify Meaningful Operations
Operations should be conceptually natural for the resource, not limited to CRUD.
Prefer Idempotent Updates
Design update APIs to be idempotent where feasible, using techniques like update masks or deduplication tokens.
UpdateFoo {
Foo newFoo;
bool update_field1; // update mask
bool update_field2; // update mask
}Ensure Compatibility
API changes must be backward compatible; deprecate features gradually and avoid breaking existing clients.
Handle Batch Mutations Wisely
Prefer client‑side batching unless atomic, transactional batch updates are essential.
Avoid Full‑Replace Risks
Full replacement updates can unintentionally overwrite new fields; use update masks to specify changed members.
Do Not Invent Custom Error Codes
Leverage standard error codes (e.g., HTTP status codes) instead of creating proprietary ones, simplifying client error handling.
References
File API history and design
Domain model design articles
Idempotency concepts
API compatibility guidelines
Google Cloud API design patterns
Microsoft API best practices
HTTP status code list
John Ousterhout’s software design philosophy
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
