API Design Basics
February 14, 2024
What is an API and what makes one "good"?
An API is an Application Programmer Interface. The term API is often used in reference to a web endpoint provided via HTTP. However, an API is not limited to web interfaces, it also applies to libraries and frameworks. Any time a programmer writes code to interact with another piece of software, they are interacting with an API. For example, writing a Spark job will require use of a SparkContext and DataFrame classes. The functions available on those classes are part of the Spark API.
You may also want to check out my blog post Making Diagrams!
Solid Engineering Foundations
Not to be confused with SOLID principles(although it is a relevant read), a good API is built on engineering basics. There's a big overlap between what makes a nice API and clean code as well. You can learn more about clean code in the book, Clean Code (Amazon link). Here are some key areas that I think are unique to API's over any other type of code.
Documentation
An API should be well-documented. API documentation should be up to date, free of errors, and provides examples and context. It is often useful for an API to separate Reference material and other materials. Reference documentation is extremely dry and defines inputs, outputs, function calls, and types and formats. Reference material does not need to explain concepts or use cases but may provide some context or "breadcrumbs" (links to other materials.) Reference material must be up to date and accurate or it will create confusion rather than clarity. Reference material can be especially useful when using languages that do not have strong support for autocompletion or inline documentation (e.g. Python versus Java). Documentation is often versioned like software so that users can find relevant documentation regardless of their API version. Documentation can often be generated from code and vice versa so there is no excuse for a poorly documented API on a large project.
Predictable and Conventional
An API should adhere to conventions. Adhering to external conventions helps provide familiarity to new users, making it easier to learn and easier to recommend and adopt. Maintaining internal conventions also reduces time to learn and time to adopt new features. Most decisions relate to convention in some way. Does your API use REST, SOAP, RPC or something different? Does it use JSON, XML, Protobuf, or something else? Are your API calls asynchronous, synchronous, or both and is there a predictable way to choose? When an API is consistent with its own conventions and those of the industry, users can be more efficient and expressive and can spend less time confirming how the API is used and more time using it.
Security
All API's need to be concerned with security. Public API's, although available to everyone and typicall not exposing private information, are subject to abuse from malicious users. They likely need to be rate limited and sometimes audited. Private API's of course need to be secured in some way and how clients obtain credentials can have a big impact on usability and whether or not the API is actually secure. If a token is never rotated and is obtained by a malicious user, that user will have indefinite access to the API. If a token is rotated too often, it can force clients to reauthenticate frequently leading to lost work and heavy traffic on both application and authentication services that can bring down systems or degrade performance. Even non-web API's must be secured. Internal libraries should sanitize client input, avoid unsafe dependencies, control access to the library itself, and not hardcode secrets.
Functional & Tested
This goes without saying but a good API should work as advertised. It should behave as documented. It should be fast and not waste resources or time. It may trade some amount of reliablity for performance but should inform the user properly. When the API encounters a problem, it should throw meaningful errors.
Maintenance and Support
When documentation fails, it is also important that clients and users can find a community or a paid expert to answer their questions. Documentation must be updated and bugs need to be patched. An API that isn't maintained or supported becomes obsolete almost immediately.
Design
API design is a dense topic spanning infrastructure, data and domain modeling, and systems thinking. As an interviewer, I would expect candidates to understand the other qualities of an API (testing, documentation, etc.) by having learned to be a good software developer. I would look to this interview round to understand your experience and systems thinking. One of the hallmarks of good systems thinking is asking good questions of the interviewer to gather requirements. Having as much information as possible is critical to making good judgment calls and demonstrates that you want to make the right choices rather than test driving the latest technology or staying entirely in your comfort zone.
Infrastructure
Infrastructure is an overloaded term in the software industry. It can mean "the systems and processes in place at a company" to "cloud compute and storage" to "a Git repository containing a Jenkinsfile and its corresponding CI/CD pipeline". Infrastructure may be different for everyone but it is generally considered "separate" from your application and "slow to change". If your team is primarily deploying their API's as containers on a Kubernetes cluster on private servers, it will require significant training and testing to migrate them to AWS Lambda functions. If you only have Oracle licenses for private servers, it is going to be hard to move your database to the cloud. These aren't impossible to do or even bad choices (in fact, they're good choices) but they will introduce more time, effort, and risk to releasing your API.
Notes for Interviews
Unless you are applying for a "cloud engineer", "operations", or "infrastructure" role, my advice here would be to use the tech stack available or, if you must, try to reframe in the context of something you understand well. I would not recommend to a client that they uproot their infrastructure in order to build an API or application. If your interviewer is asking about how to design a web endpoint, they likely don't want you to focus on migrating to the cloud or a managed service.
Architecture
Architecture is another overloaded term. In this case, I specifically want to address things like "serverless" and "microservices". These are architectural patterns/paradigms that generate a lot of hype on the Internet and within companies. They are often recommended by consultants as methods of modernizing your technical strategy (this isn't a dig, they're not completely wrong). The key takeaway I want to give is that they aren't inherently good or better than what you are doing and are objectively worse when you don't know what you are doing.
Notes for Interviews
While architecture is a really broad topic, I recommend staying away from buzzy strategies/technologies unless the role is specifically asking for it. A lot of senior developers have been burned by a hasty adoption of new architectural concepts that don't provide value for years.
Data & Domain Modeling
Data modeling and domain modeling are very similar topics with slightly different objectives. Typically, data modeling is done by a data architect or database administrator focusing on OLTP versus OLAP access patterns, dimensional/fact models, or STAR patterns (think, ERD diagrams and DDL/DML queries). Domain modeling is generally done by a senior application developer and is closely related to Object Oriented Design (think structural/behavioral/class diagrams) focusing on Domain Driven Design and Service Oriented Architecture.
Notes for Interviews
I do recommend spending at least some time here, specifically on the inputs and outputs (or requests and responses) of the system. This is a good time to check out Martin Fowler's blog Two Hard Things. You will likely need to jump between modeling and systems thinking throughout the interview.
Systems Thinking
Systems thinking has to do with understanding distributed systems and their failure modes (race conditions, cascading failures, backpressure, etc.), critical thinking and problem solving, and experience with applying tools (databases, caches, web servers, load balancers, test frameworks, etc.).
Notes for Interviews
This is where asking questions is super important. For example, instead of stating "I think we should set up a cache", try asking "What is the expected latency of this API?". Not all API's need caches, not all caches are created equal, caches introduce lots of complexity, and you might find performance gains elsewhere that get you within the requirements.
Be honest about your experience. If you have never even written code for an API, with all of the design decisions made by a senior team member, you might struggle a lot. That doesn't necessarily mean you are going to be disqualified immediately but you do want your interview to focus on what you know instead of struggling to answer questions.