COMPREHENSIVE TECHNICAL REFERENCE
API Study Guide
Beginner to Expert
A Comprehensive Guide from Fundamentals to Production-Ready Systems
Covering REST, GraphQL, gRPC, Security, Performance, System Design & More
Prepared for Sasank
April 2026
Version 1.0 | Last Updated: April 21, 2026
Preface
Dear Sasank,
Welcome to the API Study Guide — Beginner to Expert. This guide was created to serve as a single,
comprehensive reference that takes you from your very first API call all the way to designing production-
grade, globally distributed API platforms that serve millions of users.
APIs — Application Programming Interfaces — are the connective tissue of modern software. Every
mobile app you use, every website you visit, every cloud service you depend on is powered by APIs.
Understanding how to design, build, secure, test, and scale APIs is one of the most valuable skills in
software engineering today.
Why This Guide Exists
The API landscape is vast and fragmented. Information is scattered across hundreds of blog posts,
documentation sites, RFCs, and textbooks. This guide consolidates everything into a structured learning
path with practical, hands-on exercises in four major programming languages: [Link], Python, Java,
and Go.
Who This Guide Is For
● Beginners who have basic programming knowledge and want to understand APIs from the
ground up
● Intermediate developers who build APIs but want to deepen their understanding of design
principles, security, and performance
● Senior engineers preparing for system design interviews at top tech companies
● Architects who need a comprehensive reference for API governance and platform design
● QA engineers who need to understand API testing strategies and automation
● DevOps engineers who deploy, monitor, and scale API infrastructure
Prerequisites
● Basic understanding of at least one programming language (JavaScript, Python, Java, or Go
preferred)
● Familiarity with the command line / terminal
● A computer with internet access for hands-on exercises
● Basic understanding of databases (SQL or NoSQL) is helpful but not required
● No prior API experience is necessary — we start from zero
How to Get the Most Out of This Guide
1. Read actively: Don't just read — type out every code example and run it yourself
2. Complete every quiz: Each chapter ends with a quiz to reinforce concepts
3. Do the exercises: Hands-on projects are where real learning happens
4. Use the glossary: When you encounter an unfamiliar term, look it up in Appendix B
5. Build the projects: Chapter 17 contains four complete projects — build at least two of them
6. Review the interview questions: Appendix A has 100+ interview questions with model answers
Learning Objectives
Upon completing this guide, you will be able to:
Beginner Level
7. Define what an API is and explain how APIs enable software communication
8. Describe the client-server model and the HTTP request-response cycle
9. Use tools like curl, Postman, and httpie to make API calls
10. Explain HTTP methods (GET, POST, PUT, PATCH, DELETE) and when to use each
11. Interpret HTTP status codes and understand their categories (1xx–5xx)
12. Read and write JSON data structures for API payloads
13. Make API calls programmatically in [Link], Python, Java, and Go
Intermediate Level
14. Design RESTful APIs following best practices and naming conventions
15. Implement pagination, filtering, sorting, and searching in APIs
16. Write OpenAPI/Swagger specifications to document APIs
17. Implement authentication using API keys, JWT tokens, and OAuth 2.0
18. Apply rate limiting and quota management to protect APIs
19. Write comprehensive API tests (unit, integration, contract, end-to-end)
20. Handle API errors gracefully with standardized error responses
Advanced Level
21. Build GraphQL APIs with schemas, resolvers, subscriptions, and federation
22. Build gRPC services with Protocol Buffers and streaming patterns
23. Implement API gateways for routing, security, and traffic management
24. Design caching strategies (HTTP caching, Redis, CDN) for high-performance APIs
25. Set up observability with metrics, structured logging, and distributed tracing
26. Apply the OWASP API Security Top 10 to protect APIs from common vulnerabilities
Expert Level
27. Design APIs for large-scale systems like Twitter, Stripe, Uber, and Netflix
28. Implement event-driven architectures with Kafka, RabbitMQ, and AsyncAPI
29. Apply microservices patterns including saga, CQRS, and event sourcing
30. Architect multi-tenant API platforms with tenant isolation and resource governance
31. Build serverless APIs on AWS Lambda, Azure Functions, and Cloudflare Workers
32. Lead API product strategy including monetization, developer experience, and ecosystem
building
How to Use This Book
Different readers have different goals. Use the reading paths below to focus on what matters most to
you:
Your Role Priority Chapters Supplementary Chapters Estimated
Time
Frontend 1, 2, 3, 5, 6, 8, 11 4, 16, 17 (Projects 1–2) 20–30 hours
Developer
Backend Developer 1–5, 7–10, 12–13, 16–17 6, 11, 14, 15 40–60 hours
Software Architect 3–4, 9–10, 14, 18–20 5–8, 13, 15–16 30–40 hours
QA Engineer 1–3, 5, 8, 12–13 4, 9, 11, Appendix G 20–30 hours
DevOps Engineer 9, 14–16, Appendix H 8, 12–13, 17 (Project 4) 15–25 hours
Interview Prep All chapters + Appendix A + Ch Complete all quizzes 60–80 hours
20
TIP:
If you're preparing for interviews, read Chapter 20 (Case Studies & System Design) and Appendix A
(Interview Questions) last — after you've built a solid foundation through the other chapters.
System design answers are far more compelling when grounded in real implementation experience.
Table of Contents
Front Matter
Preface
Learning Objectives
How to Use This Book
Chapter 1: Introduction to APIs
1.1 What Is an API?
1.2 Evolution of APIs
1.3 Types of APIs
1.4 The API Economy
1.5 API-First Design Philosophy
1.6 Real-World API Examples
1.7 How APIs Work
1.8 API Terminology Glossary
1.9 Setting Up Your Development Environment
1.10 Your First API Call
1.11 Quiz & Exercises
Chapter 2: Web Fundamentals
2.1 HTTP Protocol Deep Dive
2.2 HTTP Methods
2.3 HTTP Status Codes
2.4 HTTP Headers
2.5 URL Structure
2.6 Request/Response Body Formats
2.7 CORS
2.8 TCP/IP, TLS, and DNS
2.9 WebSockets, SSE, and Polling
2.10 Quiz & Exercises
Chapter 3: Types of APIs
3.1 REST APIs
3.2 SOAP APIs
3.3 GraphQL APIs
3.4 gRPC APIs
3.5 WebSocket & Webhook APIs
3.6 AsyncAPI & Event-Driven APIs
3.7 Comparison Matrix
3.8 Quiz & Exercises
Chapter 4: API Design Principles
4.1 API-First Design
4.2 Resource Naming & URI Design
4.3 Pagination, Filtering, and Sorting
4.4 Error Handling & Response Design
4.5 HATEOAS & Hypermedia
4.6 Idempotency
4.7 API Contracts & OpenAPI
4.8 Quiz & Exercises
Chapter 5: RESTful API Deep Dive
Chapter 6: GraphQL & Alternatives
Chapter 7: gRPC & Protocol Buffers
Chapter 8: Authentication & Authorization
Chapter 9: Rate Limiting & Quotas
Chapter 10: Versioning & Lifecycle
Chapter 11: Documentation & Developer Experience
Chapter 12: Testing & Automation
Chapter 13: API Security
Chapter 14: API Gateways & Service Mesh
Chapter 15: Monitoring & Observability
Chapter 16: Performance & Caching
Chapter 17: Building APIs — Projects
Chapter 18: Advanced Topics
Chapter 19: API Business Models
Chapter 20: Case Studies & System Design
Appendices
Appendix A: 100+ Interview Questions with Model Answers
Appendix B: Glossary of API Terms
Appendix C: CLI Cheatsheets
Appendix D: OpenAPI/Swagger Complete Examples
Appendix E: Protocol Buffers Examples
Appendix F: Security Checklist
Appendix G: Testing Checklist
Appendix H: CI/CD Pipeline Examples
Appendix I: Sample API Contracts
Appendix J: Quiz Answers & Solutions
Back Matter
References
Acknowledgements
Index
Chapter 1: Introduction to APIs
1.1 What Is an API?
An API (Application Programming Interface) is a set of defined rules, protocols, and tools that allows
different software applications to communicate with each other. Think of an API as a contract between
two pieces of software: one piece (the client) makes a request, and the other piece (the server) provides
a response, all following a predefined format.
At its most fundamental level, an API abstracts away the internal complexity of a system and exposes
only what external consumers need. You don't need to know how Google's search algorithm works
internally to use the Google Search API — you just need to know what request to send and what
response to expect.
Analogies to Understand APIs
The Restaurant Waiter Analogy: Imagine you're at a restaurant. You (the client) want to order food. The
kitchen (the server) can prepare your meal, but you can't walk into the kitchen yourself. The waiter (the
API) takes your order (request), delivers it to the kitchen, and brings back your food (response). The
waiter is the intermediary that enables communication between you and the kitchen, following a
defined protocol (the menu).
The Electrical Outlet Analogy: An electrical outlet is an API for electricity. You don't need to understand
how the power grid works, how electricity is generated, or how it's transmitted. You just need to know
the interface: plug in a compatible device, and you get power. The outlet defines the "contract" —
voltage, current, plug shape — that both the provider and consumer must follow.
The Universal Remote Analogy: A universal remote control is like an API client. It can communicate with
many different devices (TV, sound system, streaming box) using defined protocols (infrared signals with
specific codes). Each device exposes an "API" of commands it understands (power on, volume up,
change input), and the remote sends the right signals to trigger those commands.
Figure 1.1 — How an API serves as an intermediary between client applications and backend systems
Formal Definition
In formal terms, an API defines:
33. Endpoints: The URLs or addresses where requests can be sent
34. Methods: The operations that can be performed (e.g., GET, POST, PUT, DELETE)
35. Request format: The structure and data the client must send
36. Response format: The structure and data the server will return
37. Authentication: How the client proves its identity
38. Error handling: How errors are communicated back to the client
ô TIP:
APIs are not just for web development. APIs exist everywhere in computing — your operating
system has APIs (Windows API, POSIX), programming languages have APIs (Java Standard Library),
hardware devices have APIs (GPU drivers), and even databases expose APIs (SQL is technically an
API for data access).
1.2 Evolution of APIs
APIs have evolved dramatically over the past five decades. Understanding this evolution helps you
appreciate why modern API technologies exist and what problems they solve.
Era Technology Year Key Characteristics Limitations
Early RPC RPC (Remote 1970s– Call functions on remote Platform-dependent,
Procedure 1980s machines as if they were binary protocols, hard to
Call) local; tightly coupled debug
Era Technology Year Key Characteristics Limitations
Distributed CORBA, 1990s Object-oriented distributed Complex, heavy
Objects DCOM, RMI computing; IDL-defined middleware, vendor
interfaces lock-in
Web SOAP / XML- Late XML-based messaging, Verbose XML, complex
Services RPC 1990s– WSDL contracts, WS-* specifications, heavy
2000s standards payloads
RESTful Web REST 2000– HTTP-based, stateless, Over-fetching/under-
present resource-oriented, JSON fetching, no real-time
payloads built-in
Query GraphQL 2015– Client-specified queries, Complexity, caching
Languages present single endpoint, strong type challenges, N+1 queries
system
High- gRPC 2016– Protocol Buffers, HTTP/2, Not browser-native,
Performance present bidirectional streaming, binary protocol harder to
RPC code generation debug
Event- AsyncAPI, 2017– Asynchronous, event- Eventual consistency,
Driven Webhooks present driven, message brokers, complex debugging,
real-time delivery guarantees
The REST Revolution
In 2000, Roy Fielding published his doctoral dissertation defining Representational State Transfer
(REST). REST leveraged the existing HTTP protocol and introduced a simpler, more intuitive way to build
web APIs compared to the heavyweight SOAP standard. REST's simplicity — combined with the rise of
JSON over XML — sparked an explosion in API adoption that continues today.
The Modern API Landscape
Today, organizations typically use multiple API styles simultaneously. A company might expose REST
APIs for public consumption, use gRPC for internal microservice communication, offer GraphQL for
mobile clients that need flexible queries, and use webhooks for event notifications. The key is choosing
the right tool for each use case.
✅BEST PRACTICE:
Don't adopt a new API technology just because it's trendy. Choose your API style based on your
specific requirements: REST for CRUD operations and broad compatibility, GraphQL for complex
client queries with varying data needs, gRPC for high-performance inter-service communication, and
webhooks for event-driven integrations.
1.3 Types of APIs
APIs can be classified by their accessibility (who can use them) and by their architectural style (how
they work). Let's first examine the accessibility classification:
Type Description Audience Examples
Public (Open) Available to any developer, often External Google Maps API,
APIs with free tiers. May require API key developers, OpenWeatherMap,
registration. public Twitter/X API
Private Used within an organization only. Internal teams Internal user service,
(Internal) Not exposed externally. Powers inventory management API
APIs internal applications.
Partner APIs Shared with specific business Vetted Supplier integrations, B2B
partners under formal agreements partners data exchange
(contracts, SLAs).
Composite Combine multiple API calls into a Internal or Order processing
APIs single request to reduce network partner (combines inventory +
overhead. payment + shipping)
1.4 The API Economy
The API economy refers to the set of business models and practices that have emerged around APIs as
products. APIs are no longer just technical implementation details — they are revenue-generating
products, distribution channels, and competitive advantages.
Key statistics:
● The global API management market is valued at over $5 billion and is projected to grow to $20+
billion by 2030
● Over 90% of developers use APIs in their applications
● Salesforce generates over 50% of its revenue through APIs
● Expedia generates nearly 90% of its revenue through API-powered partner integrations
● Stripe processes hundreds of billions of dollars annually, all through its APIs
TIP:
When evaluating your career growth, note that API-related skills consistently rank among the most
in-demand in software engineering job postings. Understanding API design, security, and scalability
can significantly boost your market value.
1.5 API-First Design Philosophy
API-First design means that the API is treated as a "first-class citizen" in the development process.
Instead of building an application and then bolting on an API, you design the API first — define its
contract, get stakeholder feedback, and then build the implementation behind it.
Benefits of API-First:
● Parallel development: Frontend and backend teams can work simultaneously once the API
contract is defined
● Better design: Thinking about the API upfront leads to cleaner, more consistent interfaces
● Reusability: APIs designed as standalone products are more reusable across applications
● Documentation: API-first naturally produces documentation (from the specification)
● Testing: Contract tests can be written before implementation begins
Companies that follow API-First: Stripe, Twilio, Plaid, SendGrid, Shopify, Slack.
1.6 Real-World API Examples
Company API What It Does Why It Matters
Google Maps API Geocoding, directions, place Powers location features in
search, Street View millions of apps
Company API What It Does Why It Matters
Stripe Payments API Process payments, manage Gold standard for API design
subscriptions, handle refunds and DX
Twilio Communications SMS, voice calls, video, email Programmatic access to
API (SendGrid) telecom infrastructure
X (Twitter) Twitter API Post tweets, read timelines, Enables entire ecosystem of
search, manage users social media tools
Spotify Web API Search music, manage playlists, Powers third-party music
get recommendations applications
GitHub REST + GraphQL Manage repos, issues, PRs, Enables CI/CD tools, project
APIs actions, users management integrations
1.7 How APIs Work: The Request-Response Cycle
At its core, most API communication follows a simple request-response pattern:
39. Client constructs a request: The client application builds an HTTP request containing the
method, URL, headers, and optionally a body
40. DNS resolution: The domain name in the URL is resolved to an IP address
41. TCP connection: A TCP connection is established between client and server (including TLS
handshake for HTTPS)
42. Request sent: The HTTP request is transmitted over the established connection
43. Server processes: The server receives the request, routes it to the appropriate handler, executes
business logic, accesses databases/services as needed
44. Response returned: The server constructs an HTTP response with a status code, headers, and
body, then sends it back
45. Client processes: The client receives and processes the response data
Figure 1.2 — The complete API request-response cycle from client to server
1.8 API Terminology Glossary
Term Definition
Endpoint A specific URL where an API can be accessed. Example:
[Link]
Resource An object or entity that the API manages. Examples: user, product, order, post.
Method The HTTP verb indicating the action: GET (read), POST (create), PUT (replace),
PATCH (update), DELETE (remove).
Header Key-value metadata sent with requests/responses. Used for authentication,
content type, caching, etc.
Payload / The data sent in the request or response body, typically in JSON or XML format.
Body
Status Code A three-digit number in the response indicating the result: 200 OK, 404 Not Found,
500 Server Error, etc.
Authentication Verifying the identity of the caller. "Who are you?"
Authorization Determining what an authenticated caller is allowed to do. "What can you access?"
Rate Limit A restriction on how many API calls a client can make within a time period.
SDK Software Development Kit — a pre-built library that wraps API calls in a language-
specific interface.
Term Definition
Webhook A callback mechanism where the server pushes data to the client's URL when an
event occurs.
Idempotent An operation that produces the same result regardless of how many times it's
executed.
1.9 Setting Up Your Development Environment
Before making your first API call, you need to set up your development tools. Here's what to install:
Essential Tools
Tool Purpose Install Command / Download
[Link] 20+ JavaScript runtime for building APIs Download from [Link] or use nvm
install 20
Python Python runtime for building APIs Download from [Link] or use pyenv
3.11+ install 3.11
Java JDK 21+ Java runtime for Spring Boot APIs Download from [Link] or use
sdkman install java 21
Go 1.22+ Go runtime for high-performance APIs Download from [Link]
VS Code Code editor with API development Download from [Link]
extensions
Postman GUI tool for testing and exploring APIs Download from [Link]
curl Command-line HTTP client (pre- Pre-installed on most systems; Windows:
installed on macOS/Linux) install via winget
httpie User-friendly command-line HTTP client pip install httpie or brew
install httpie
Docker Container runtime for databases and Download from [Link]
deployment
Git Version control Download from [Link]
VS Code Extensions for API Development
● REST Client — Make HTTP requests directly from VS Code
● Thunder Client — Lightweight Postman alternative inside VS Code
● OpenAPI Editor — YAML/JSON editor with OpenAPI schema validation
● Prettier — Auto-format JSON, YAML, and code files
● Docker — Manage containers from VS Code
1.10 Your First API Call
Let's make your first API call using JSONPlaceholder, a free public API for testing and prototyping. We'll
fetch a list of posts from [Link] .
Using curl
BASH
curl -X GET [Link] \ -H "Accept:
application/json" | python -m [Link]
Response:
JSON
{ "userId": 1, "id": 1, "title": "sunt aut facere repellat
provident occaecati excepturi optio reprehenderit", "body": "quia et
suscipit\nsuscipit recusandae consequuntur..." }
Using httpie
BASH
http GET [Link]
Using [Link] (fetch)
JAVASCRIPT
// [Link] const response = await
fetch('[Link] const post = await
[Link](); [Link]('Post Title:', [Link]); [Link]('Post
Body:', [Link]); [Link]('Status:', [Link]);
Using Python (requests)
PYTHON
# first_api_call.py import requests response =
[Link]('[Link] post =
[Link]() print(f"Post Title: {post['title']}") print(f"Post Body:
{post['body']}") print(f"Status Code: {response.status_code}")
Using Java (HttpClient)
JAVA
import [Link].*; import [Link]; public class FirstApiCall {
public static void main(String[] args) throws Exception { HttpClient
client = [Link](); HttpRequest request =
[Link]()
.uri([Link]("[Link]
.header("Accept", "application/json") .GET()
.build(); HttpResponse<String> response = [Link](
request, [Link]() );
[Link]("Status: " + [Link]());
[Link]("Body: " + [Link]()); } }
Using Go (net/http)
GO
package main import ( "fmt" "io" "net/http" ) func main() {
resp, err := [Link]("[Link] if
err != nil { [Link]("Error:", err) return }
defer [Link]() body, _ := [Link]([Link])
[Link]("Status:", [Link]) [Link]("Body:",
string(body)) }
TIP:
JSONPlaceholder ([Link]) is a free, public API that requires no
authentication. It supports all HTTP methods (GET, POST, PUT, PATCH, DELETE) and is perfect for
learning and prototyping. Other great free APIs for practice include: [Link] (request
inspection), [Link] (user CRUD), and [Link] (fun facts).
WARNING:
Never hardcode API keys, tokens, or secrets directly in your source code. Even in tutorials and
learning projects, develop the habit of using environment variables or configuration files.
Accidentally committing credentials to a Git repository is one of the most common and costly
security mistakes in the industry.
✅BEST PRACTICE:
Always check the HTTP status code before processing the response body. A non-2xx status code
means the request was not successful. Build this habit from day one — it will save you hours of
debugging mysterious errors in production.
1.11 Chapter 1 Quiz
Q1. What does API stand for, and what is its primary purpose?
Q2. Name three real-world analogies for an API and explain how each relates to the concept.
Q3. What is the difference between a Public API, a Private API, and a Partner API?
Q4. Roy Fielding defined REST in his doctoral dissertation. In what year was it published?
Q5. What are the four main components of an HTTP request?
Q6. What tool would you use to make API calls from the command line? Name two options.
Q7. What status code would you expect from a successful GET request?
Q8. Explain the difference between authentication and authorization.
Q9. What is an API endpoint? Give an example.
Q10. What percentage of Salesforce's revenue is reportedly generated through APIs?
Q11. Name three advantages of API-First design.
Q12. What is an idempotent operation? Why does it matter for APIs?
Q13. What is the difference between SOAP and REST at a high level?
Q14. What data format has largely replaced XML for modern APIs, and why?
Q15. Write a curl command to make a GET request to [Link] with an
Accept header of application/json.
Hands-on Exercise: Build an API Consumer
Objective: Build a command-line application that fetches all posts from JSONPlaceholder, displays them
in a formatted list, allows the user to select a post by ID to see its full details and comments, and
handles errors gracefully.
Requirements:
46. Fetch all posts from [Link]
47. Display a numbered list with title and userId
48. Accept user input to select a post ID
49. Fetch and display the selected post's details
50. Fetch and display comments for that post from /posts/{id}/comments
51. Handle network errors and invalid input gracefully
Solution (Python):
PYTHON
import requests import sys BASE_URL = "[Link]
def fetch_posts(): """Fetch all posts from the API.""" try:
response = [Link](f"{BASE_URL}/posts", timeout=10)
response.raise_for_status() return [Link]() except
[Link] as e: print(f"Error fetching posts: {e}")
[Link](1) def fetch_post(post_id): """Fetch a single post by ID."""
response = [Link](f"{BASE_URL}/posts/{post_id}", timeout=10)
response.raise_for_status() return [Link]() def
fetch_comments(post_id): """Fetch comments for a specific post."""
response = [Link](f"{BASE_URL}/posts/{post_id}/comments", timeout=10)
response.raise_for_status() return [Link]() def main():
print("=" * 60) print(" JSONPlaceholder API Explorer") print("=" *
60) posts = fetch_posts() print(f"\nFound {len(posts)} posts:\n")
for post in posts[:10]: # Show first 10 print(f" [{post['id']:3d}]
{post['title'][:50]}...") print(f"\n ... and {len(posts) - 10} more
posts") while True: try: post_id =
int(input("\nEnter post ID (1-100) or 0 to quit: ")) if post_id
== 0: break if post_id < 1 or post_id > 100:
print("Invalid ID. Please enter 1-100.") continue
post = fetch_post(post_id) print(f"\n--- Post #{post['id']} ---")
print(f"Title: {post['title']}") print(f"Author (userId):
{post['userId']}") print(f"Body:\n{post['body']}")
comments = fetch_comments(post_id) print(f"\n Comments
({len(comments)}):") for c in comments: print(f"
- {c['name']} ({c['email']})") print(f"
{c['body'][:80]}...") except ValueError: print("Please
enter a valid number.") except [Link] as e:
print(f"API error: {e}") if __name__ == "__main__": main()
Chapter 2: Web Fundamentals
2.1 HTTP Protocol Deep Dive
The Hypertext Transfer Protocol (HTTP) is the foundation of data communication on the Web and the
primary protocol used by APIs. Understanding HTTP deeply is essential for any API developer.
HTTP Version Comparison
Feature HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/3 (QUIC)
Year 1996 1997 2015 2022
Connections New connection per Persistent (keep- Multiplexed Multiplexed
request alive) streams (QUIC/UDP)
Head-of-line Yes Yes (at TCP level) Solved at HTTP Fully solved (UDP)
blocking level
Header No No HPACK QPACK
compression
Server push No No Yes Yes
Protocol TCP TCP TCP + TLS QUIC (UDP + TLS
1.3)
Encryption Optional Optional Practically Built-in
required (mandatory)
HTTP/1.1 is still the most widely deployed version. It introduced persistent connections (keep-alive),
chunked transfer encoding, and the Host header (enabling virtual hosting). However, it suffers from
head-of-line blocking — if one request is slow, subsequent requests on the same connection must wait.
HTTP/2 solved many HTTP/1.1 problems by introducing multiplexing (multiple streams over a single TCP
connection), header compression (HPACK), and server push. For APIs, HTTP/2 significantly reduces
latency, especially when making many parallel requests.
HTTP/3 replaces TCP with QUIC, a UDP-based transport protocol with built-in TLS 1.3 encryption. This
eliminates TCP head-of-line blocking entirely and provides faster connection establishment (0-RTT in
many cases). HTTP/3 is particularly beneficial for mobile API clients on unreliable networks.
Figure 2.1 — The HTTP protocol as the foundation of RESTful APIs
2.2 HTTP Methods
HTTP defines several request methods (also called "verbs") that indicate the desired action to be
performed on the identified resource:
Method Purpose Has Idempotent? Safe? Cacheable?
Body?
GET Retrieve a resource or collection No Yes Yes Yes
POST Create a new resource Yes No No No
PUT Replace a resource entirely Yes Yes No No
PATCH Partially update a resource Yes No* No No
DELETE Remove a resource Optional Yes No No
HEAD Same as GET but returns only headers No Yes Yes Yes
OPTIONS Describe communication options No Yes Yes No
(CORS preflight)
TRACE Diagnostic: echoes back the received No Yes Yes No
request
*PATCH can be idempotent if implemented with JSON Merge Patch, but is not guaranteed to be.
WARNING:
Never use GET requests for operations that modify data. GET requests can be cached by browsers
and proxies, bookmarked by users, and replayed by crawlers. Using GET for destructive operations
(e.g., GET /delete-account) is a serious security vulnerability and design flaw.
When to Use PUT vs PATCH
PUT replaces the entire resource. If you PUT a user object, you must send all fields — any field you omit
will be set to null or its default value. PATCH applies a partial update. You only send the fields you want
to change.
JSON — PUT Request (full replacement)
PUT /api/users/42 { "name": "Sasank", "email": "sasank@[Link]",
"role": "admin", "department": "engineering", "phone": "+1-555-0100"
}
JSON — PATCH Request (partial update)
PATCH /api/users/42 { "email": "[Link]@[Link]" }
2.3 HTTP Status Codes — Complete Reference
1xx — Informational
Code Name Description
100 Continue Server has received request headers; client should proceed to send
body
101 Switching Protocols Server is switching to protocol requested in Upgrade header (e.g.,
WebSocket)
102 Processing Server has received request and is processing (WebDAV)
103 Early Hints Server sends preliminary headers before final response
(preloading)
2xx — Success
Code Name When to Use
200 OK Successful GET, PUT, PATCH, or DELETE. The most common success
code.
201 Created Successful POST that created a new resource. Include Location header
pointing to the new resource.
202 Accepted Request accepted for async processing. The result isn't ready yet.
204 No Content Successful request with no response body. Common for DELETE
operations.
206 Partial Content Response contains only part of the resource (range requests for file
downloads).
3xx — Redirection
Code Name When to Use
301 Moved Resource has permanently moved to new URL. Clients should update
Permanently bookmarks.
302 Found Temporary redirect. Client should use original URL for future requests.
304 Not Modified Resource hasn't changed since last request (conditional GET with
ETags). Saves bandwidth.
307 Temporary Like 302, but the method must not change (POST stays POST).
Redirect
308 Permanent Like 301, but the method must not change.
Redirect
4xx — Client Errors
Code Name When to Use
400 Bad Request Malformed request syntax, invalid parameters, or validation failure.
401 Unauthorized Authentication required or credentials invalid. Should include
WWW-Authenticate header.
403 Forbidden Authenticated but not authorized to access this resource.
404 Not Found Resource does not exist at the specified URL.
Code Name When to Use
405 Method Not HTTP method not supported for this endpoint. Include Allow header
Allowed listing supported methods.
409 Conflict Request conflicts with current state (e.g., duplicate email,
concurrent edit).
413 Payload Too Large Request body exceeds server limits.
415 Unsupported Media Content-Type not supported (e.g., sending XML to a JSON-only
Type endpoint).
422 Unprocessable Request is well-formed but semantically invalid (e.g., email format
Entity wrong).
429 Too Many Requests Rate limit exceeded. Include Retry-After header.
5xx — Server Errors
Code Name When to Use
500 Internal Server Error Generic server error. Something unexpected went wrong.
501 Not Implemented Server doesn't support the functionality required to fulfill the
request.
502 Bad Gateway Server acting as gateway received invalid response from
upstream.
503 Service Unavailable Server temporarily overloaded or under maintenance. Include
Retry-After.
504 Gateway Timeout Gateway/proxy didn't receive response from upstream in time.
✅BEST PRACTICE:
Use the most specific status code that applies. Don't return 200 for everything and hide the actual
status in the response body. Don't return 500 for client errors. The status code is the first thing
automated systems (load balancers, monitoring, client libraries) check — make it meaningful.
2.4 HTTP Headers
Common Request Headers
Header Purpose Example
Accept Media types the client accepts application/json
Content-Type Media type of request body application/json;
charset=utf-8
Authorization Authentication credentials Bearer eyJhbGciOi...
User-Agent Client software identification MyApp/1.0 ([Link])
Accept- Compression algorithms the client gzip, br, deflate
Encoding supports
If-None-Match Conditional request (ETag-based caching) "33a64df551425fcc55e"
X-Request-ID Unique request identifier for tracing 550e8400-e29b-41d4-a716
Common Response Headers
Header Purpose Example
Content-Type Media type of response body application/json
Cache-Control Caching directives max-age=3600, public
ETag Resource version identifier for caching "33a64df551425fcc55e"
Location URL of newly created or redirected /api/users/42
resource
X-RateLimit- Number of requests remaining in window 95
Remaining
Retry-After Seconds to wait before retrying (429/503) 30
2.5 URL Structure
Understanding URL anatomy is critical for API design:
URL ANATOMY
[Link]
=1#section2 |_____| |_______________|___|_|________________|
|_________________________________| |_______| scheme host port
path query parameters fragment
Component Description Example
Scheme Protocol (always HTTPS for production APIs) https
Host Domain name or IP address of the server [Link]
Port Network port (443 for HTTPS, 80 for HTTP) 443 (default, can be omitted)
Path Resource location, hierarchical structure /v2/users/42/posts
Query Filtering, sorting, pagination parameters ?status=published&page=1
Fragment Client-side anchor (not sent to server) #section2
2.6 Request/Response Body Formats
Format Content-Type Pros Cons Use Cases
JSON application/json Lightweight, human- No schema Most
readable, native JS enforcement, no REST/GraphQL
support, widely comments, APIs
supported limited types
XML application/xml Schema validation Verbose, complex SOAP,
(XSD), namespaces, parsing, heavy enterprise,
mature tooling payloads legacy
Protocol application/protobuf Very compact, fast Not human- gRPC, inter-
Buffers serialization, strong readable, service
typing requires proto
definitions
Form application/x-www- Simple key-value Flat structure, no HTML forms,
Data form-urlencoded pairs, browser-native nesting, encoding OAuth token
overhead requests
Multipart multipart/form-data File uploads, mixed Complex parsing, File uploads,
content types large overhead image
for small data processing
2.7 CORS (Cross-Origin Resource Sharing)
CORS is a browser security mechanism that restricts web pages from making requests to a different
domain than the one that served the page. When your frontend at [Link] tries
to call an API at [Link] the browser will block the request unless the API server
explicitly allows it through CORS headers.
How CORS Works
52. Simple requests (GET, POST with standard headers): Browser adds Origin header and sends
the request directly. Server responds with Access-Control-Allow-Origin.
53. Preflight requests (PUT, DELETE, custom headers): Browser first sends an OPTIONS request to
check if the actual request is allowed. If the server responds with appropriate CORS headers, the
browser proceeds with the actual request.
CORS Headers
Header Purpose Example Value
Access-Control- Which origins can access the API [Link]
Allow-Origin or *
Access-Control- Which HTTP methods are allowed GET, POST, PUT, DELETE
Allow-Methods
Access-Control- Which custom headers are allowed Authorization, Content-
Allow-Headers Type
Access-Control-Max- How long preflight results are cached 86400
Age (seconds)
Access-Control- Whether cookies/auth headers are true
Allow-Credentials allowed
WARNING:
Setting Access-Control-Allow-Origin: * allows any website to call your API. This is fine for
public APIs but dangerous for private APIs that rely on cookies or session-based authentication.
Never use * with Access-Control-Allow-Credentials: true — browsers will reject this
combination.
[Link] — Express CORS Configuration
const express = require('express'); const cors = require('cors'); const app =
express(); [Link](cors({ origin: ['[Link]
'[Link] methods: ['GET', 'POST', 'PUT', 'PATCH',
'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, maxAge: 86400 }));
PYTHON — FastAPI CORS Configuration
from fastapi import FastAPI from [Link] import
CORSMiddleware app = FastAPI() app.add_middleware( CORSMiddleware,
allow_origins=["[Link] allow_credentials=True,
allow_methods=["*"], allow_headers=["*"], max_age=86400, )
2.8 TCP/IP, TLS, and DNS Fundamentals
TCP Three-Way Handshake
Before any HTTP data can be exchanged, the client and server must establish a TCP connection using a
three-step process:
54. SYN: Client sends a SYN (synchronize) packet to the server
55. SYN-ACK: Server responds with SYN-ACK (synchronize-acknowledge)
56. ACK: Client sends ACK (acknowledge) — connection established
TLS Handshake (HTTPS)
After TCP, an additional TLS handshake occurs for HTTPS:
57. Client sends ClientHello with supported cipher suites and TLS versions
58. Server responds with ServerHello, chosen cipher suite, and its certificate
59. Client verifies server certificate against trusted Certificate Authorities
60. Both sides derive session keys through key exchange (ECDHE in TLS 1.3)
61. Encrypted communication begins
TLS 1.3 improvements: Only 1-RTT handshake (vs 2-RTT in TLS 1.2), supports 0-RTT resumption,
removed outdated cipher suites, faster and more secure.
2.9 WebSockets, SSE, and Polling
Technology Direction Protocol Best For Limitations
Short Polling Client → Server HTTP Simple use cases, low Wasteful, high latency,
(repeated) update frequency server load
Long Polling Client → Server HTTP Near-real-time with Connection management
(held open) HTTP compatibility complexity, timeouts
SSE (Server- Server → Client HTTP Live feeds, One-directional only,
Sent Events) (one-way) notifications, limited browser
dashboards connections
WebSocket Bidirectional WS/WSS Chat, gaming, real- Connection management,
time collaboration proxy/firewall issues
TIP:
For most real-time API use cases (notifications, live updates, dashboards), Server-Sent Events (SSE)
is the simplest and most reliable choice. It works over standard HTTP, supports automatic
reconnection, and is well-supported by browsers. Only reach for WebSockets when you truly need
bidirectional communication (e.g., chat, collaborative editing).
2.10 Chapter 2 Quiz
Q1. What are the main differences between HTTP/1.1 and HTTP/2?
Q2. Which HTTP methods are idempotent? Which are safe?
Q3. When should you return 401 vs 403?
Q4. What is the difference between PUT and PATCH?
Q5. What status code should you return after successfully creating a resource via POST?
Q6. Explain what CORS is and why browsers enforce it.
Q7. What is a preflight request and when does the browser send one?
Q8. Describe the TCP three-way handshake.
Q9. What is the ETag header used for?
Q10. Compare WebSockets, SSE, and Long Polling. When would you choose each?
Q11. What Content-Type header should you set when sending JSON data?
Q12. What does HTTP/3 use instead of TCP, and what advantage does this provide?
Q13. What is the significance of the 429 status code and which header should accompany it?
Q14. Explain the difference between the Accept and Content-Type headers.
Q15. Why should production APIs always use HTTPS (TLS) rather than plain HTTP?
Chapter 3: Types of APIs
3.1 REST APIs
REST (Representational State Transfer) is an architectural style for distributed systems, defined by Roy
Fielding in 2000. REST APIs are the most widely used API type on the web today.
REST Constraints
62. Client-Server: Separation of concerns between UI and data storage/logic
63. Stateless: Each request contains all information needed to process it; no session state stored on
server
64. Cacheable: Responses must define whether they are cacheable
65. Uniform Interface: Standardized way to interact with resources (resource identification via URIs,
manipulation through representations, self-descriptive messages, HATEOAS)
66. Layered System: Client cannot tell whether it's connected directly to the server or through
intermediaries
67. Code on Demand (optional): Server can extend client functionality by sending executable code
Richardson Maturity Model
The Richardson Maturity Model measures how "RESTful" an API truly is:
Level Name Description Example
Level 0 The Swamp Single endpoint, single HTTP method POST /api with action in
of POX (usually POST). Essentially RPC over body
HTTP.
Level 1 Resources Individual URIs for different resources, POST /users, POST
but still uses only POST. /orders
Level 2 HTTP Verbs Uses proper HTTP methods (GET, POST, GET /users, POST
PUT, DELETE) with resources. Most APIs /users, DELETE
are here. /users/42
Level 3 Hypermedia Responses include links to related Response includes
(HATEOAS) resources and available actions. True "_links": {"self":
REST. ..., "orders": ...}
3.2 SOAP APIs
SOAP (Simple Object Access Protocol) is a protocol for exchanging structured information using XML.
While less popular for new development, SOAP remains prevalent in banking, healthcare, and enterprise
environments.
Key SOAP Components:
● WSDL (Web Services Description Language): XML document describing the service, its
operations, messages, and bindings
● SOAP Envelope: XML wrapper containing the header and body of the message
● WS-Security: Standard for securing SOAP messages (encryption, digital signatures)
● WS-ReliableMessaging: Guaranteed message delivery
● WS-Transaction: Distributed transaction support
XML — SOAP Request Example
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope
xmlns:soap="[Link] <soap:Header>
<auth:credentials xmlns:auth="[Link]
<auth:username>sasank</auth:username>
<auth:token>abc123</auth:token> </auth:credentials>
</soap:Header> <soap:Body> <m:GetUser
xmlns:m="[Link] <m:UserId>42</m:UserId>
</m:GetUser> </soap:Body> </soap:Envelope>
3.3 GraphQL APIs
GraphQL is a query language for APIs developed by Facebook (now Meta) and open-sourced in 2015. It
lets clients request exactly the data they need — no more, no less.
GRAPHQL — Schema Definition
type User { id: ID! name: String! email: String! posts:
[Post!]! } type Post { id: ID! title: String! body: String!
author: User! comments: [Comment!]! } type Query { user(id: ID!):
User users(limit: Int, offset: Int): [User!]! post(id: ID!): Post }
type Mutation { createUser(name: String!, email: String!): User!
createPost(title: String!, body: String!, authorId: ID!): Post! }
GRAPHQL — Client Query
query GetUserWithPosts { user(id: "42") { name email
posts { title comments { body
} } } }
3.4 gRPC APIs
gRPC (Google Remote Procedure Call) is a high-performance, open-source framework that uses Protocol
Buffers for serialization and HTTP/2 for transport.
PROTOBUF — Service Definition
syntax = "proto3"; package userservice; service UserService { rpc
GetUser (GetUserRequest) returns (User); rpc ListUsers (ListUsersRequest)
returns (stream User); // Server streaming rpc CreateUser
(CreateUserRequest) returns (User); } message User { int32 id = 1;
string name = 2; string email = 3; string role = 4; } message
GetUserRequest { int32 id = 1; } message ListUsersRequest { int32
page_size = 1; string page_token = 2; } message CreateUserRequest {
string name = 1; string email = 2; }
3.5 WebSocket & Webhook APIs
WebSocket APIs provide full-duplex communication over a single TCP connection. After an HTTP
handshake upgrades the connection to WebSocket, both client and server can send messages freely
without the overhead of HTTP headers for each message.
Webhook APIs reverse the traditional request-response model. Instead of the client polling for updates,
the server sends HTTP POST requests to a client-specified URL when events occur.
JAVASCRIPT — WebSocket Client
const ws = new WebSocket('[Link] [Link] = () => {
[Link]('Connected'); [Link]([Link]({ type: 'subscribe',
channel: 'orders' })); }; [Link] = (event) => { const data =
[Link]([Link]); [Link]('Received:', data); }; [Link] =
() => [Link]('Disconnected'); [Link] = (err) =>
[Link]('Error:', err);
3.6 AsyncAPI & Event-Driven APIs
Event-driven APIs use message brokers (Kafka, RabbitMQ, MQTT) to enable asynchronous, decoupled
communication between services. The AsyncAPI specification provides a standard way to document
these APIs, similar to how OpenAPI documents REST APIs.
3.7 Comprehensive Comparison Matrix
Figure 3.1 — API architectural styles comparison overview
Criteria REST SOAP GraphQL gRPC WebSocket Webhook
Protocol HTTP/HTTP HTTP, HTTP/HTTPS HTTP/2 WS/WSS HTTP/HTTP
S SMTP, TCP S
Data JSON, XML XML only JSON Protocol Any JSON
Format Buffers
Direction Request- Request- Request- Unary + Bidirection Server →
Response Response Response Streaming al Client
Real-time No No Yes Yes Yes Yes (push)
(polling) (subscription (streaming)
s)
Criteria REST SOAP GraphQL gRPC WebSocket Webhook
Type Safety Weak Strong Strong Strong None None
(JSON (XSD/WSD (schema) (protobuf)
Schema) L)
Performanc Good Poor (XML Good Excellent Excellent Good
e overhead) (flexible) (binary)
Browser Excellent Limited Excellent Via gRPC- Excellent N/A
Support Web
Caching HTTP Complex Difficult Not built-in N/A N/A
caching
Learning Low High Medium Medium- Low- Low
Curve High Medium
Best For CRUD, Enterprise, Complex Microservice Chat, Notification
public APIs banking queries, s, IoT gaming s
mobile
✅BEST PRACTICE:
Most organizations benefit from a polyglot API strategy: REST for external/public APIs (broadest
compatibility), gRPC for internal microservice communication (performance), GraphQL for BFF
(Backend for Frontend) layers serving mobile clients, and webhooks for event notifications to
partners. Don't force one style on every use case.
3.8 Chapter 3 Quiz
Q1. List the six REST architectural constraints.
Q2. What is the Richardson Maturity Model and what level are most real-world APIs at?
Q3. What is HATEOAS and why do few APIs implement it in practice?
Q4. Describe the over-fetching and under-fetching problems that GraphQL solves.
Q5. What serialization format does gRPC use, and why is it faster than JSON?
Q6. When would you choose SOAP over REST for a new project?
Q7. Explain the difference between a WebSocket connection and an HTTP connection.
Q8. What is a webhook? How does it differ from polling?
Q9. What transport protocol does gRPC use, and what advantages does it provide?
Q10. Name three gRPC streaming types and give a use case for each.
Chapter 4: API Design Principles
4.1 API-First Design
In API-First design, you write the API specification (OpenAPI/Swagger) before writing any code. This
specification becomes the single source of truth that frontend teams, backend teams, QA, and
documentation writers all work from simultaneously.
API-First Workflow
68. Define requirements: Gather use cases, identify resources, map data models
69. Write the specification: Create an OpenAPI 3.1 YAML/JSON document
70. Review with stakeholders: Get feedback from frontend, mobile, QA, and product teams
71. Generate mocks: Use Prism or similar tools to create a mock server from the spec
72. Parallel development: Frontend builds against mocks; backend implements the spec
73. Contract testing: Automated tests verify implementation matches the specification
74. Generate documentation: Auto-generate interactive docs from the spec
4.2 Resource Naming & URI Design
Naming Rules
Rule Good ✓ Bad ✗ Why
Use nouns, /users /getUsers HTTP methods
not verbs already express the
action
Use plurals /users /user Consistency:
for /users (list) and
collections /users/42 (single)
Use kebab- /user-profiles /userProfiles URLs are case-
case insensitive by
convention
Nest for /users/42/posts /getUserPosts?userId=42 Hierarchy expresses
relationshi ownership/relations
ps hip
Limit /users/42/posts /users/42/posts/5/comments/3/l Deep nesting
nesting ikes creates rigid, hard-
depth (≤3) to-maintain URLs
Use query /users?role=adm /admin-users Filtering shouldn't
params for in create new
filtering endpoints
URI Design Patterns
REST URI Examples
# Collection operations GET /api/v1/users # List all users
(with pagination) POST /api/v1/users # Create a new user #
Single resource operations GET /api/v1/users/42 # Get user by
ID PUT /api/v1/users/42 # Replace user PATCH /api/v1/users/42
# Partially update user DELETE /api/v1/users/42 # Delete user #
Sub-resources GET /api/v1/users/42/posts # Get posts by user 42 POST
/api/v1/users/42/posts # Create post for user 42 # Filtering, sorting,
searching GET /api/v1/users?role=admin&status=active GET
/api/v1/users?sort=-created_at,name GET /api/v1/users?search=sasank #
Pagination GET /api/v1/users?page=2&per_page=25 GET
/api/v1/users?cursor=eyJpZCI6MTAwfQ==&limit=25 # Actions (when CRUD doesn't
fit) POST /api/v1/users/42/activate POST /api/v1/orders/99/cancel
4.3 Pagination, Filtering, and Sorting
Pagination Strategies
Strategy How It Works Pros Cons Best For
Offset- ?page=3&per_page=25 or Simple, Slow on large datasets Small
based ?offset=50&limit=25 supports (OFFSET scans), datasets,
"jump to inconsistent with admin panels
page N" concurrent writes
Cursor- ?cursor=abc123&limit=25 Consistent No "jump to page N", Infinite scroll,
based results, fast cursor must be opaque mobile, large
at scale datasets
(indexed
queries)
Keyset- ?after_id=100&limit=25 Very fast Requires sortable, Time-series
based (uses indexed unique column; no data, feeds
column), random page access
simple to
understand
Pagination Response Format
JSON — Cursor-based Pagination Response
{ "data": [ { "id": 101, "name": "User A" }, { "id": 102,
"name": "User B" } ], "pagination": { "next_cursor":
"eyJpZCI6MTAyfQ==", "prev_cursor": "eyJpZCI6MTAxfQ==",
"has_more": true, "total_count": 1250 } }
4.4 Error Handling & Response Design
RFC 7807 — Problem Details for HTTP APIs
RFC 7807 defines a standard format for error responses, ensuring consistency across your API:
JSON — RFC 7807 Error Response
{ "type": "[Link] "title":
"Validation Error", "status": 422, "detail": "The request body
contains invalid fields.", "instance": "/api/v1/users", "errors": [
{ "field": "email", "message": "Must be a valid email
address", "code": "INVALID_FORMAT" }, {
"field": "age", "message": "Must be between 13 and 150",
"code": "OUT_OF_RANGE" } ], "trace_id": "abc-123-def-456" }
WARNING:
Never expose internal implementation details in error messages sent to clients. Stack traces,
database table names, internal IP addresses, or SQL queries in error responses are information
disclosure vulnerabilities. Log detailed errors server-side and return sanitized, user-friendly
messages to clients.
4.5 HATEOAS & Hypermedia
HATEOAS (Hypermedia as the Engine of Application State) means that API responses include hyperlinks
to related resources and available actions. The client doesn't need to hardcode URL patterns — it
discovers them by following links.
JSON — HATEOAS Response (HAL format)
{ "id": 42, "name": "Sasank", "email": "sasank@[Link]",
"status": "active", "_links": { "self": { "href":
"/api/v1/users/42" }, "posts": { "href": "/api/v1/users/42/posts" },
"deactivate": { "href": "/api/v1/users/42/deactivate", "method": "POST" },
"update": { "href": "/api/v1/users/42", "method": "PATCH" } } }
4.6 Idempotency
An operation is idempotent if performing it multiple times has the same effect as performing it once.
This is critical for reliability — if a network failure occurs after a client sends a request but before it
receives a response, the client can safely retry without causing duplicate side effects.
Method Idempotent? Example
GET Yes Fetching a user always returns the same user
PUT Yes Replacing a user with the same data has no additional effect
DELETE Yes Deleting an already-deleted resource returns 404 but causes no harm
POST No Each POST /orders creates a new order
PATCH Maybe Depends on implementation (absolute vs relative changes)
Idempotency Keys
For non-idempotent operations like POST, implement idempotency keys: the client sends a unique key
(usually a UUID) in the Idempotency-Key header. The server stores the result and returns the same
response for duplicate keys.
BASH — Request with Idempotency Key
curl -X POST [Link] \ -H "Authorization:
Bearer sk_live_abc123" \ -H "Idempotency-Key: 550e8400-e29b-41d4-a716-
446655440000" \ -H "Content-Type: application/json" \ -d '{"amount":
2000, "currency": "usd", "customer": "cus_123"}'
✅BEST PRACTICE:
Implement idempotency keys for any API endpoint that creates resources or triggers side effects
(payments, emails, order placement). Stripe's API is the gold standard — every POST request
supports an Idempotency-Key header, making retries safe and ensuring at-most-once semantics.
4.7 API Contracts & OpenAPI
An API contract is a formal specification that defines what the API looks like, what inputs it expects, and
what outputs it returns. The OpenAPI Specification (OAS), formerly known as Swagger, is the industry
standard for documenting REST APIs.
YAML — OpenAPI 3.1 Example (excerpt)
openapi: 3.1.0 info: title: User Management API version: 1.0.0
description: API for managing users servers: - url:
[Link] paths: /users: get: summary: List all
users parameters: - name: page in: query
schema: type: integer default: 1 - name:
per_page in: query schema: type: integer
default: 25 maximum: 100 responses: '200':
description: Successful response content:
application/json: schema: type: object
properties: data: type: array
items: $ref: '#/components/schemas/User'
pagination: $ref: '#/components/schemas/Pagination'
post: summary: Create a new user requestBody: required:
true content: application/json: schema:
$ref: '#/components/schemas/CreateUserRequest' responses:
'201': description: User created headers:
Location: schema: type: string
content: application/json: schema:
$ref: '#/components/schemas/User' '422': description:
Validation error content: application/json:
schema: $ref: '#/components/schemas/Error' components:
schemas: User: type: object properties: id:
type: integer name: type: string email:
type: string format: email created_at: type:
string format: date-time CreateUserRequest: type: object
required: [name, email] properties: name: type:
string minLength: 1 maxLength: 100 email:
type: string format: email
4.8 Chapter 4 Quiz
Q1. What is API-First design and what are its three biggest advantages?
Q2. Should API resource names be nouns or verbs? Explain why.
Q3. Compare offset-based and cursor-based pagination. Which scales better?
Q4. What is RFC 7807 and what problem does it solve?
Q5. What is an idempotency key and when should you use one?
Q6. What is HATEOAS? Give an example of a HATEOAS response.
Q7. Design the URI structure for a blog API with users, posts, comments, and tags.
Q8. What is the OpenAPI Specification and how does it benefit API development?
Chapter 5: RESTful API Deep Dive
5.1 REST Constraints in Practice
Let's examine each REST constraint with practical examples that show how they affect real-world API
design and implementation.
Statelessness in Practice
Statelessness means the server does not store any client session state between requests. Every request
must contain all the information needed to process it — including authentication credentials (typically a
JWT token in the Authorization header).
JAVASCRIPT — Stateless Request (each request is self-contained)
// Every request includes the auth token — no server-side session const
response = await fetch('[Link] { headers:
{ 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIs...',
'Accept': 'application/json' } });
5.2 Advanced HTTP Methods
JSON Patch (RFC 6902)
JSON Patch is a format for describing changes to a JSON document using an array of operations:
JSON — JSON Patch Operations
PATCH /api/v1/users/42 Content-Type: application/json-patch+json [ {
"op": "replace", "path": "/email", "value": "new@[Link]" }, { "op":
"add", "path": "/phone", "value": "+1-555-0100" }, { "op": "remove",
"path": "/nickname" }, { "op": "test", "path": "/version", "value": 5 } ]
Conditional Requests with ETags
ETags enable optimistic concurrency control and efficient caching:
BASH — Conditional Update with ETag
# 1. GET the resource (server returns ETag) GET /api/v1/users/42 # Response:
ETag: "v5-abc123" # 2. Update only if the resource hasn't changed (prevents
lost updates) PUT /api/v1/users/42 If-Match: "v5-abc123" Content-Type:
application/json {"name": "Sasank Updated", "email": "sasank@[Link]"}
# If another client modified it first → 412 Precondition Failed # If it
matches → 200 OK with new ETag
5.3 Building a Complete RESTful API — [Link]/Express
Project Structure
TEXT — Project Directory Structure
task-api/ ├── src/ │ ├── config/ │ │ ├── [Link] │ │ └── [Link]
│ ├── middleware/ │ │ ├── [Link] │ │ ├── [Link] │ │
├── [Link] │ │ └── [Link] │ ├── models/ │ │ ├──
[Link] │ │ └── [Link] │ ├── routes/ │ │ ├── [Link] │ │
├── [Link] │ │ └── [Link] │ ├── controllers/ │ │
├── [Link] │ │ ├── [Link] │ │ └──
[Link] │ ├── services/ │ │ ├── [Link] │ │ └──
[Link] │ └── [Link] ├── tests/ ├── Dockerfile ├── docker-
[Link] ├── [Link] └── .env
Main Application ([Link])
JAVASCRIPT
const express = require('express'); const cors = require('cors'); const
helmet = require('helmet'); const morgan = require('morgan'); const {
connectDB } = require('./config/database'); const { errorHandler } =
require('./middleware/errorHandler'); const authRoutes =
require('./routes/[Link]'); const userRoutes =
require('./routes/[Link]'); const taskRoutes =
require('./routes/[Link]'); const app = express(); // Security &
parsing middleware [Link](helmet()); [Link](cors({ origin:
[Link].ALLOWED_ORIGINS?.split(',') })); [Link](morgan('combined'));
[Link]([Link]({ limit: '10mb' })); // Health check [Link]('/health',
(req, res) => { [Link]({ status: 'healthy', timestamp: new
Date().toISOString() }); }); // Routes [Link]('/api/v1/auth', authRoutes);
[Link]('/api/v1/users', userRoutes); [Link]('/api/v1/tasks', taskRoutes);
// Global error handler [Link](errorHandler); // Start server const PORT =
[Link] || 3000; connectDB().then(() => { [Link](PORT, () =>
[Link](`API running on port ${PORT}`)); });
Task Controller with Pagination
JAVASCRIPT
const Task = require('../models/Task'); [Link] = async (req, res,
next) => { try { const { page = 1,
per_page = 25, status, priority, sort =
'-created_at', search } = [Link]; // Build
filter const filter = { user: [Link] }; if (status)
[Link] = status; if (priority) [Link] = priority;
if (search) { filter.$text = { $search: search }; }
// Parse sort const sortObj = {};
[Link](',').forEach(field => { if ([Link]('-')) {
sortObj[[Link](1)] = -1; } else {
sortObj[field] = 1; } }); const skip =
(parseInt(page) - 1) * parseInt(per_page); const limit =
[Link](parseInt(per_page), 100); const [tasks, total] = await
[Link]([
[Link](filter).sort(sortObj).skip(skip).limit(limit),
[Link](filter) ]); [Link]({ data:
tasks, pagination: { page: parseInt(page),
per_page: limit, total, total_pages:
[Link](total / limit), has_more: skip + [Link] <
total } }); } catch (error) { next(error);
} };
TIP:
Always cap the per_page parameter with a maximum value (e.g., 100). Without this, a client could
request per_page=1000000, potentially overwhelming your database and crashing your server.
Validate and sanitize all query parameters.
5.4 Building the Same API — Python/FastAPI
PYTHON
from fastapi import FastAPI, Query, Depends, HTTPException, status from
pydantic import BaseModel, EmailStr from typing import Optional from datetime
import datetime app = FastAPI(title="Task API", version="1.0.0") class
TaskCreate(BaseModel): title: str description: Optional[str] = None
priority: str = "medium" due_date: Optional[datetime] = None class
TaskResponse(BaseModel): id: int title: str description:
Optional[str] status: str priority: str created_at: datetime
updated_at: datetime class PaginatedResponse(BaseModel): data:
list[TaskResponse] total: int page: int per_page: int
has_more: bool @[Link]("/api/v1/tasks", response_model=PaginatedResponse)
async def list_tasks( page: int = Query(1, ge=1), per_page: int =
Query(25, ge=1, le=100), status: Optional[str] = None, priority:
Optional[str] = None, sort: str = "-created_at", search:
Optional[str] = None, ): """List tasks with filtering, sorting, and
pagination.""" # Build query (simplified — real implementation uses
SQLAlchemy/Tortoise) tasks = await [Link](status=status,
priority=priority) \ .offset((page - 1) * per_page) \
.limit(per_page) total = await [Link]() return
PaginatedResponse( data=tasks, total=total,
page=page, per_page=per_page, has_more=(page * per_page) <
total ) @[Link]("/api/v1/tasks", status_code=status.HTTP_201_CREATED)
async def create_task(task: TaskCreate): """Create a new task."""
new_task = await [Link](**[Link]()) return new_task
5.5 Chapter 5 Quiz
Q1. Explain the difference between JSON Patch and JSON Merge Patch.
Q2. How do ETags enable optimistic concurrency control?
Q3. What HTTP status code should you return if an If-Match condition fails?
Q4. Why is it important to cap the per_page parameter in pagination?
Q5. Describe the typical folder structure for a REST API project and explain the purpose of each layer.
Chapter 6: GraphQL & Alternatives
6.1 GraphQL Fundamentals
GraphQL provides a complete description of the data in your API through a type system. Clients send
queries that exactly describe the data they need, and the server returns exactly that data — nothing
more, nothing less.
Building a GraphQL Server — [Link] (Apollo Server)
JAVASCRIPT
const { ApolloServer } = require('@apollo/server'); const {
startStandaloneServer } = require('@apollo/server/standalone'); const
typeDefs = `#graphql type User { id: ID! name: String!
email: String! posts: [Post!]! } type Post { id: ID!
title: String! body: String! author: User! createdAt:
String! } type Query { users(limit: Int = 10, offset: Int =
0): [User!]! user(id: ID!): User posts(authorId: ID):
[Post!]! } type Mutation { createUser(input:
CreateUserInput!): User! createPost(input: CreatePostInput!): Post!
} input CreateUserInput { name: String! email: String!
} input CreatePostInput { title: String! body: String!
authorId: ID! } `; const resolvers = { Query: { users: (_, {
limit, offset }) => [Link]({ limit, offset }),
user: (_, { id }) => [Link](id), posts: (_, {
authorId }) => authorId ? [Link](authorId) :
[Link]() }, User: { posts: (user) =>
[Link]([Link]) }, Mutation: { createUser: (_,
{ input }) => [Link](input), createPost: (_, { input }) =>
[Link](input) } }; const server = new ApolloServer({ typeDefs,
resolvers }); const { url } = await startStandaloneServer(server, { listen: {
port: 4000 } }); [Link](`GraphQL server running at ${url}`);
The N+1 Problem and DataLoader
When a GraphQL query requests nested data (e.g., users with their posts), a naive resolver makes 1
query for users + N queries for each user's posts. The DataLoader pattern batches and caches these
lookups:
JAVASCRIPT
const DataLoader = require('dataloader'); // Batch function: receives an
array of user IDs, returns posts grouped by userId const postsByUserLoader =
new DataLoader(async (userIds) => { const posts = await
[Link](userIds); // Single DB query // Group posts by
userId and return in same order as input IDs return [Link](id =>
[Link](p => [Link] === id)); }); // Resolver uses DataLoader
instead of direct DB call const resolvers = { User: { posts:
(user) => [Link]([Link]) } };
WARNING:
Without DataLoader or a similar batching solution, GraphQL APIs can suffer severe N+1 query
performance issues. For a query returning 100 users with posts, a naive implementation executes
101 database queries (1 for users + 100 for posts). DataLoader reduces this to 2 queries. Always
implement DataLoader for nested resolvers in production.
6.2 GraphQL Security
Attack Vector Mitigation Implementation
Deep nesting attacks Query depth limiting Max depth of 10 levels
Wide queries Query complexity analysis Assign cost to fields, cap total cost
Introspection abuse Disable introspection in production introspection: false in config
Batch attacks Limit batch size Max 10 queries per batch request
Resource exhaustion Persisted queries Only allow pre-approved query
hashes
6.3 Chapter 6 Quiz
Q1. What is the N+1 problem in GraphQL, and how does DataLoader solve it?
Q2. Compare GraphQL queries and mutations. When do you use each?
Q3. What are GraphQL subscriptions and what transport do they typically use?
Q4. Name three GraphQL security concerns and their mitigations.
Q5. When would you choose GraphQL over REST?
Chapter 7: gRPC & Protocol Buffers
7.1 Protocol Buffers (proto3)
Protocol Buffers (protobuf) is Google's language-neutral, platform-neutral mechanism for serializing
structured data. It is more compact, faster to serialize/deserialize, and more strongly typed than JSON.
Proto3 Syntax Reference
PROTOBUF
syntax = "proto3"; package ecommerce; import
"google/protobuf/[Link]"; // Enum definition enum OrderStatus {
ORDER_STATUS_UNSPECIFIED = 0; ORDER_STATUS_PENDING = 1;
ORDER_STATUS_CONFIRMED = 2; ORDER_STATUS_SHIPPED = 3;
ORDER_STATUS_DELIVERED = 4; ORDER_STATUS_CANCELLED = 5; } // Message
with various field types message Product { int32 id = 1; string name
= 2; string description = 3; double price = 4; int32
stock_quantity = 5; repeated string tags = 6; // Array of
strings map<string, string> metadata = 7; // Key-value pairs
[Link] created_at = 8; } message Order { int32 id =
1; int32 customer_id = 2; repeated OrderItem items = 3;
OrderStatus status = 4; double total_amount = 5; // Nested message
message OrderItem { int32 product_id = 1; int32 quantity = 2;
double unit_price = 3; } } // Service with all four streaming types
service OrderService { // Unary RPC rpc CreateOrder
(CreateOrderRequest) returns (Order); // Server streaming — server
sends a stream of updates rpc TrackOrder (TrackOrderRequest) returns
(stream OrderUpdate); // Client streaming — client sends a stream of
items rpc UploadBulkOrders (stream Order) returns (BulkOrderResponse);
// Bidirectional streaming — both stream simultaneously rpc LiveOrderChat
(stream ChatMessage) returns (stream ChatMessage); }
7.2 gRPC Streaming Patterns
Pattern Description Use Cases
Unary Client sends one request, server sends one CRUD operations, simple lookups
response (like REST)
Server Streaming Client sends one request, server streams Real-time updates, progress
multiple responses tracking, live feeds
Client Streaming Client streams multiple messages, server File upload, bulk data ingestion,
sends one response sensor data
Bidirectional Both client and server stream messages Chat, real-time collaboration,
Streaming independently gaming
gRPC Server in Go
GO
package main import ( "context" "log" "net" pb
"myapp/proto/userservice" "[Link]/grpc" ) type server struct
{ [Link] } func (s *server) GetUser(ctx
[Link], req *[Link]) (*[Link], error) { // Fetch
user from database user := &[Link]{ Id: [Link], Name:
"Sasank", Email: "sasank@[Link]", Role: "admin", }
return user, nil } func main() { lis, err := [Link]("tcp", ":50051")
if err != nil { [Link]("Failed to listen: %v", err) } s
:= [Link]() [Link](s, &server{})
[Link]("gRPC server listening on :50051") if err := [Link](lis);
err != nil { [Link]("Failed to serve: %v", err) } }
✅BEST PRACTICE:
When designing proto files, always use field numbers 1–15 for the most frequently accessed fields
(they use only 1 byte for encoding). Fields 16–2047 use 2 bytes. Never reuse or change field
numbers after deployment — this breaks backward compatibility. Mark deprecated fields as
reserved.
7.3 Chapter 7 Quiz
Q1. What are the four gRPC streaming types? Give a use case for each.
Q2. Why is Protocol Buffers faster than JSON for serialization?
Q3. What transport protocol does gRPC use, and why?
Q4. How do you handle backward compatibility in proto files?
Q5. What is gRPC-Web and why is it needed?
Chapter 8: Authentication & Authorization
8.1 Authentication vs Authorization
Aspect Authentication (AuthN) Authorization (AuthZ)
Question "Who are you?" "What are you allowed to do?"
When First — before authorization After authentication succeeds
Mechanism Credentials (password, token, Permissions, roles, policies
certificate)
Failure Code 401 Unauthorized 403 Forbidden
Example Logging in with username/password Admin can delete users; regular user
cannot
8.2 API Authentication Methods
Method Security Level Complexity Best For
API Keys Low-Medium Low Public APIs, server-to-server, rate limiting
Basic Auth Low (requires Very Low Internal tools, simple scripts (over HTTPS
HTTPS) only)
JWT (Bearer Medium-High Medium Single-page apps, mobile apps,
Token) microservices
OAuth 2.0 High High Third-party integrations, delegated access
Mutual TLS (mTLS) Very High High Zero-trust, service mesh, banking
8.3 OAuth 2.0 Deep Dive
Figure 8.1 — OAuth 2.0 authorization flows overview
OAuth 2.0 Grant Types
Grant Type Use Case Client Type Flow
Authorization Web apps, mobile apps, Public or User authenticates via browser →
Code + PKCE SPAs Confidential auth code → exchange for tokens
Client Machine-to-machine Confidential Client sends credentials directly →
Credentials communication receives access token
Device Code TVs, IoT, CLI tools (devices Public Device displays code → user
without keyboards) authorizes on another device
Grant Type Use Case Client Type Flow
Refresh Token Renewing expired access Any Client sends refresh token →
tokens receives new access token
WARNING:
The Implicit Grant and Resource Owner Password Credentials (ROPC) grant types are deprecated in
OAuth 2.1 and should NEVER be used in new implementations. The Implicit Grant exposes tokens in
URLs (browser history, referrer headers). ROPC requires the client to handle the user's password
directly. Always use Authorization Code + PKCE instead.
8.4 JWT (JSON Web Tokens)
A JWT consists of three Base64URL-encoded parts separated by dots: [Link]
JSON — JWT Header
{ "alg": "RS256", "typ": "JWT", "kid": "key-2026-04" }
JSON — JWT Payload (Claims)
{ "sub": "user_42", "name": "Sasank", "email":
"sasank@[Link]", "roles": ["admin", "user"], "iat": 1777000000,
"exp": 1777003600, "iss": "[Link] "aud":
"[Link] }
JWT Implementation — [Link]
JAVASCRIPT
const jwt = require('jsonwebtoken'); const { readFileSync } = require('fs');
// Use RS256 (asymmetric) in production — never HS256 with shared secrets
const PRIVATE_KEY = readFileSync('./keys/[Link]'); const PUBLIC_KEY =
readFileSync('./keys/[Link]'); // Generate token function
generateAccessToken(user) { return [Link]( { sub:
[Link], name: [Link], roles: [Link]
}, PRIVATE_KEY, { algorithm: 'RS256',
expiresIn: '15m', // Short-lived access token issuer:
'[Link] audience: '[Link]
} ); } function generateRefreshToken(user) { return [Link](
{ sub: [Link], type: 'refresh' }, PRIVATE_KEY, { algorithm:
'RS256', expiresIn: '7d' } ); } // Verify token middleware function
authenticate(req, res, next) { const authHeader =
[Link]; if (!authHeader?.startsWith('Bearer ')) {
return [Link](401).json({ error: 'Missing authentication token' }); }
const token = [Link](' ')[1]; try { const decoded =
[Link](token, PUBLIC_KEY, { algorithms: ['RS256'],
issuer: '[Link] audience:
'[Link] }); [Link] = decoded;
next(); } catch (err) { if ([Link] === 'TokenExpiredError') {
return [Link](401).json({ error: 'Token expired' }); }
return [Link](401).json({ error: 'Invalid token' }); } }
RBAC (Role-Based Access Control) Middleware
JAVASCRIPT
function authorize(...requiredRoles) { return (req, res, next) => {
if (![Link]) { return [Link](401).json({ error: 'Not
authenticated' }); } const hasRole = [Link](role
=> [Link](role)); if (!hasRole) { return
[Link](403).json({ error: 'Forbidden',
message: `Required roles: ${[Link](', ')}` });
} next(); }; } // Usage in routes
[Link]('/api/v1/users/:id', authenticate, authorize('admin'),
deleteUser); [Link]('/api/v1/users', authenticate, authorize('admin',
'manager'), listUsers); [Link]('/api/v1/users/me', authenticate,
getMyProfile); // Any authenticated user
✅BEST PRACTICE:
Keep access tokens short-lived (5–15 minutes) and use refresh tokens for renewal. Store refresh
tokens securely (HTTP-only cookies for web apps, secure storage for mobile). Implement token
revocation by maintaining a blocklist of revoked tokens or using token versioning. Never store JWTs
in localStorage — it's vulnerable to XSS attacks.
8.5 Chapter 8 Quiz
Q1. What is the difference between authentication and authorization?
Q2. Name the three parts of a JWT and describe what each contains.
Q3. Why is RS256 preferred over HS256 for JWT signing in microservices?
Q4. Explain the OAuth 2.0 Authorization Code + PKCE flow step by step.
Q5. Why should you never store JWTs in localStorage?
Chapter 9: Rate Limiting & Quotas
9.1 Rate Limiting Algorithms
Algorithm How It Works Pros Cons
Fixed Window Counter per time window (e.g., 100 Simple, low Burst at window
req/min). Resets at window memory edges (can get 2x
boundary. limit)
Sliding Store timestamp of each request. Accurate, no burst High memory (stores
Window Log Count requests in sliding window. issue all timestamps)
Sliding Weighted average of current and Low memory, Approximate (not
Window previous window counters. smooth rate 100% accurate)
Counter limiting
Token Bucket Bucket fills with tokens at fixed Allows controlled Slightly more complex
rate. Each request consumes a bursts, smooth
token.
Leaky Bucket Requests enter a queue processed Smooth output Requests may be
at fixed rate. Overflow is dropped. rate, prevents delayed or dropped
bursts
Token Bucket Implementation — [Link] with Redis
JAVASCRIPT
const Redis = require('ioredis'); const redis = new Redis(); async function
tokenBucketLimiter(key, maxTokens, refillRate) { const now = [Link]();
const bucketKey = `ratelimit:${key}`; // Lua script for atomic token
bucket operation const luaScript = ` local key = KEYS[1]
local max_tokens = tonumber(ARGV[1]) local refill_rate =
tonumber(ARGV[2]) local now = tonumber(ARGV[3])
local bucket = [Link]('HMGET', key, 'tokens', 'last_refill')
local tokens = tonumber(bucket[1]) or max_tokens local last_refill =
tonumber(bucket[2]) or now -- Calculate tokens to add since
last refill local elapsed = (now - last_refill) / 1000 tokens
= [Link](max_tokens, tokens + (elapsed * refill_rate)) if
tokens >= 1 then tokens = tokens - 1
[Link]('HMSET', key, 'tokens', tokens, 'last_refill', now)
[Link]('EXPIRE', key, [Link](max_tokens / refill_rate) + 1)
return {1, [Link](tokens)} else [Link]('HMSET',
key, 'tokens', tokens, 'last_refill', now) return {0,
[Link](tokens)} end `; const [allowed, remaining] =
await [Link]( luaScript, 1, bucketKey, maxTokens, refillRate, now
); return { allowed: allowed === 1, remaining }; } // Express
middleware function rateLimitMiddleware(maxTokens = 100, refillRate = 10) {
return async (req, res, next) => { const key = [Link]; // or
[Link]?.id or API key const result = await tokenBucketLimiter(key,
maxTokens, refillRate); [Link]('X-RateLimit-Limit', maxTokens);
[Link]('X-RateLimit-Remaining', [Link]); if
(![Link]) { [Link]('Retry-After', [Link](1 /
refillRate)); return [Link](429).json({
error: 'Too Many Requests', message: 'Rate limit exceeded.
Please retry later.', retry_after: [Link](1 / refillRate)
}); } next(); }; }
TIP:
Always include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset
headers in every response (not just 429 responses). This allows well-behaved clients to proactively
slow down before hitting the limit, resulting in a better experience for everyone.
Chapter 10: Versioning & Lifecycle
10.1 API Versioning Strategies
Strategy Example Pros Cons
URI Path /api/v1/users Explicit, easy to Pollutes URIs, can
understand, easy to break HATEOAS
route
Query /api/users?version=1 Optional, backward- Easy to forget, can
Parameter compatible default break caching
Custom X-API-Version: 1 Clean URIs, explicit Hidden, harder to
Header test in browser
Content Accept: RESTful, media type Complex, not widely
Negotiation application/[Link].v1+json driven understood
10.2 Breaking vs Non-Breaking Changes
Non-Breaking (Safe) ✓ Breaking (Dangerous) ✗
Adding a new optional field to request/response Removing a field from the response
Adding a new endpoint Renaming an existing endpoint
Adding a new optional query parameter Changing a field's data type
Adding a new enum value Making a previously optional field required
Relaxing a validation constraint Tightening a validation constraint
Adding a new HTTP method to an existing resource Changing the meaning of an existing field
Increasing a rate limit Decreasing a rate limit
10.3 API Lifecycle
75. Design: Write OpenAPI spec, review with stakeholders, mock and test
76. Develop: Implement the API, write tests, generate documentation
77. Test: Unit, integration, contract, performance, and security testing
78. Deploy: Deploy to staging, then production with canary/blue-green
79. Monitor: Track latency, errors, usage, SLOs
80. Evolve: Add features with non-breaking changes, bump minor version
81. Deprecate: Announce deprecation, set Sunset header, provide migration guide
82. Sunset: Remove the old version after sufficient notice period (minimum 6–12 months)
✅BEST PRACTICE:
When deprecating an API version, use the Sunset header (RFC 8594) and Deprecation header.
Send proactive email notifications to API consumers 6 months, 3 months, 1 month, and 1 week
before sunset. Provide a detailed migration guide and offer support during the transition.
Chapter 11: Documentation & Developer
Experience
11.1 Why Documentation Matters
Studies consistently show that documentation quality is the #1 factor developers consider when
choosing an API. Poor documentation leads to increased support costs, slower adoption, higher churn,
and frustrated developers.
Great API Docs Include
● Getting Started guide — First successful API call in under 5 minutes
● Authentication guide — How to obtain and use credentials
● Endpoint reference — Every endpoint with parameters, request/response examples
● Error reference — All possible errors with troubleshooting guides
● Code examples — In at least 4 popular languages
● Interactive playground — "Try it" functionality with sandbox environment
● SDKs & libraries — Official client libraries for popular languages
● Changelog — What changed in each version
● Rate limit documentation — Limits, headers, and how to handle 429s
Documentation Tools Comparison
Tool Type Pricing Key Features
Swagger UI Open Source Free Interactive docs from OpenAPI spec, try-it-out
Redoc Open Source Free / Pro Beautiful three-panel docs, responsive, fast
Stoplight Platform Freemium Visual API design + docs + mocking
ReadMe Platform Paid Developer hub, API metrics, personalized docs
Mintlify Platform Freemium Beautiful docs, AI-powered search, MDX
Chapter 12: Testing & Automation
12.1 The API Testing Pyramid
Level Scope Speed Quantity Tools
Unit Tests Individual functions, Very Fast Many (70%) Jest, pytest, JUnit, Go
validators, services testing
Integration API endpoints with real Medium Moderate Supertest, httpx,
Tests database (20%) MockMvc
Contract Tests Consumer-provider contract Fast Few per Pact, Spring Cloud
verification consumer Contract
E2E Tests Full flow across services Slow Few (10%) Newman, k6, custom
scripts
Performance Load, stress, spike testing Slow Few k6, Artillery, Locust,
Tests JMeter
Integration Test Example — [Link] (Jest + Supertest)
JAVASCRIPT
const request = require('supertest'); const app = require('../src/app');
const { connectDB, closeDB, clearDB } = require('./helpers/db');
describe('POST /api/v1/users', () => { beforeAll(() => connectDB());
afterEach(() => clearDB()); afterAll(() => closeDB()); it('should
create a user with valid data', async () => { const res = await
request(app) .post('/api/v1/users') .send({ name:
'Sasank', email: 'sasank@[Link]' }) .set('Authorization',
`Bearer ${testToken}`) .expect('Content-Type', /json/)
.expect(201); expect([Link]).toMatchObject({ name:
'Sasank', email: 'sasank@[Link]' });
expect([Link]).toHaveProperty('id');
expect([Link]).toMatch(/\/api\/v1\/users\/\w+/); });
it('should return 422 for invalid email', async () => { const res =
await request(app) .post('/api/v1/users') .send({
name: 'Test', email: 'not-an-email' }) .set('Authorization',
`Bearer ${testToken}`) .expect(422);
expect([Link]).toContainEqual( [Link]({
field: 'email' }) ); }); it('should return 409 for duplicate
email', async () => { // Create first user await
request(app).post('/api/v1/users') .send({ name: 'User1', email:
'dup@[Link]' }) .set('Authorization', `Bearer
${testToken}`); // Try to create duplicate const res = await
request(app) .post('/api/v1/users') .send({ name:
'User2', email: 'dup@[Link]' }) .set('Authorization',
`Bearer ${testToken}`) .expect(409);
expect([Link]).toContain('already exists'); }); });
Performance Test — k6
JAVASCRIPT
import http from 'k6/http'; import { check, sleep } from 'k6'; import { Rate,
Trend } from 'k6/metrics'; const errorRate = new Rate('errors'); const
apiDuration = new Trend('api_duration'); export const options = {
stages: [ { duration: '1m', target: 50 }, // Ramp up to 50 users
{ duration: '3m', target: 50 }, // Stay at 50 users { duration:
'1m', target: 200 }, // Spike to 200 users { duration: '2m', target:
200 }, // Stay at 200 users { duration: '1m', target: 0 }, //
Ramp down ], thresholds: { http_req_duration: ['p(95)<500'],
// 95% of requests under 500ms errors: ['rate<0.01'], //
Error rate under 1% }, }; export default function () { const res =
[Link]('[Link] { headers: {
Authorization: `Bearer ${__ENV.API_TOKEN}` }, }); check(res, {
'status is 200': (r) => [Link] === 200, 'response time < 500ms':
(r) => [Link] < 500, }); [Link]([Link] !==
200); [Link]([Link]); sleep(1); }
TIP:
Run performance tests against a staging environment that mirrors production (same database size,
same infrastructure). Testing against an empty database with a single instance gives misleading
results. Include realistic data volumes and concurrent users in your performance test scenarios.
Chapter 13: API Security
13.1 OWASP API Security Top 10 (2023)
# Vulnerability Description Mitigation
1 Broken Object Level User can access other users' Always verify the
Authorization (BOLA) objects by changing the ID in the authenticated user owns
URL the requested resource
2 Broken Authentication Weak auth mechanisms, no brute- Strong auth, rate limiting on
force protection, exposed tokens login, short-lived tokens
3 Broken Object API exposes object properties the Allowlist response fields,
Property Level Auth user shouldn't see/modify (mass validate input against
assignment) schema
4 Unrestricted Resource No limits on requests, file sizes, Rate limiting, pagination
Consumption batch operations, query limits, input size limits
complexity
5 Broken Function Level Regular user can access admin RBAC, deny-by-default,
Authorization (BFLA) endpoints check roles on every request
6 Unrestricted Access to Automated abuse of business logic Bot detection, CAPTCHA,
Sensitive Business (ticket scalping, content scraping) behavioral analysis
Flows
7 Server-Side Request API fetches user-provided URLs, Validate/allowlist URLs,
Forgery (SSRF) enabling access to internal deny private IP ranges
services
8 Security Default configs, verbose errors, Hardened configs, disable
Misconfiguration unnecessary features enabled debug, security headers
9 Improper Inventory Forgotten APIs, undocumented API inventory, automated
Management endpoints, old versions still discovery, version lifecycle
running management
10 Unsafe Consumption Blindly trusting data from third- Validate all external API
of APIs party APIs without validation responses, timeout, circuit
breaking
BOLA Prevention Example
JAVASCRIPT
// VULNERABLE — any authenticated user can access any order
[Link]('/api/v1/orders/:id', authenticate, async (req, res) => { const
order = await [Link]([Link]); [Link](order); // No
ownership check! }); // SECURE — verify the authenticated user owns the
resource [Link]('/api/v1/orders/:id', authenticate, async (req, res) => {
const order = await [Link]([Link]); if (!order) {
return [Link](404).json({ error: 'Order not found' }); } //
CRITICAL: Check ownership if ([Link]() !== [Link] &&
) { return [Link](403).json({
error: 'Access denied' }); } [Link](order); });
WARNING:
BOLA (Broken Object Level Authorization) is the #1 API vulnerability year after year. It's deceptively
simple: if your API has an endpoint like GET /orders/123, can user A access user B's order by
simply changing the ID? Every endpoint that returns user-specific data MUST verify ownership. This
check should be implemented at the service/middleware layer, not left to individual developers to
remember.
13.2 Security Headers
JAVASCRIPT — Setting Security Headers with Helmet
const helmet = require('helmet'); [Link](helmet({
contentSecurityPolicy: { directives: { defaultSrc:
["'self'"], scriptSrc: ["'self'"], } }, hsts: {
maxAge: 31536000, includeSubDomains: true, preload: true },
referrerPolicy: { policy: 'strict-origin-when-cross-origin' } })); //
Additional custom security headers [Link]((req, res, next) => {
[Link]('X-Content-Type-Options', 'nosniff'); [Link]('X-Frame-Options',
'DENY'); [Link]('Permissions-Policy', 'camera=(), microphone=(),
geolocation=()'); next(); });
Chapter 14: API Gateways & Service Mesh
14.1 What Is an API Gateway?
An API Gateway is a server that sits between clients and backend services, acting as a reverse proxy to
route requests, enforce policies, and aggregate results. It serves as the single entry point for all API
traffic.
Figure 14.1 — API gateway as a single entry point for microservices
API Gateway Functions
● Request routing — Route requests to appropriate backend services
● Authentication — Verify tokens, API keys at the edge
● Rate limiting — Throttle requests per consumer
● Load balancing — Distribute traffic across service instances
● Caching — Cache responses to reduce backend load
● Request/Response transformation — Modify headers, body, protocol translation
● Logging & monitoring — Centralized access logging and metrics
● Circuit breaking — Prevent cascade failures
API Gateway Comparison
Gateway Type Protocol Key Strength Pricing
Kong Open Source / HTTP, gRPC, Plugin ecosystem, Lua Free /
Enterprise WebSocket extensibility Enterprise
AWS API Managed Cloud HTTP, Serverless integration, Pay-per-
Gateway WebSocket Lambda request
Azure API Managed Cloud HTTP, Enterprise features, policy Tiered
Management WebSocket engine
Gateway Type Protocol Key Strength Pricing
Apigee Managed Cloud HTTP Analytics, monetization, Enterprise
(Google) developer portal
Tyk Open Source / HTTP, gRPC, Go-based, GraphQL-native Free / Paid
Cloud GraphQL
NGINX Open Source / HTTP, gRPC, Performance, battle- Free / Plus
Plus TCP/UDP tested
14.2 Service Mesh
A service mesh provides infrastructure-layer networking for service-to-service communication. It
handles concerns like traffic management, security (mTLS), and observability without requiring changes
to application code.
Feature API Gateway Service Mesh
Position Edge (client → services) Internal (service → service)
Focus North-south traffic East-west traffic
Auth Client authentication Service-to-service mTLS
Examples Kong, AWS API GW, Apigee Istio, Linkerd, Consul Connect
Chapter 15: Monitoring & Observability
15.1 The Three Pillars of Observability
Figure 15.1 — The three pillars of system observability: Logs, Metrics, and Traces
Pillar What It Captures Best For Tools
Metrics Numeric measurements over Dashboards, alerting, trends, Prometheus,
time (counters, gauges, capacity planning Datadog,
histograms) CloudWatch
Logs Timestamped text records of Debugging, audit trail, error ELK Stack, Loki,
discrete events investigation Splunk
Traces End-to-end journey of a request Latency analysis, dependency Jaeger, Zipkin,
across services mapping, root cause analysis Honeycomb
15.2 Key API Metrics
Metric What It Measures Target Example
Latency (p50) Median response time < 100ms
Metric What It Measures Target Example
Latency (p95) 95th percentile response time < 300ms
Latency (p99) 99th percentile response time < 1000ms
Error Rate Percentage of 5xx responses < 0.1%
Throughput (RPS) Requests per second Varies by service
Availability Uptime percentage 99.9% (three nines)
Saturation CPU, memory, connection pool utilization < 70%
SLA/SLO/SLI Definitions
Term Definition Example
SLI (Service Level A quantitative metric measuring service p95 latency, error rate,
Indicator) performance availability
SLO (Service Level A target value for an SLI that the team "p95 latency < 300ms over 30-
Objective) commits to day window"
SLA (Service Level A contractual commitment with "99.9% uptime or 10% credit
Agreement) consequences for SLO breach refund"
Structured Logging Example — [Link]
JAVASCRIPT
const pino = require('pino'); const logger = pino({ level:
[Link].LOG_LEVEL || 'info', formatters: { level: (label) =>
({ level: label }), }, timestamp: () => `,"timestamp":"${new
Date().toISOString()}"`, }); // Request logging middleware [Link]((req,
res, next) => { const requestId = [Link]['x-request-id'] ||
[Link](); [Link] = [Link]({ requestId, method:
[Link], path: [Link] }); const start = [Link]();
[Link]('finish', () => { [Link]({ statusCode:
[Link], duration: [Link]() - start,
userAgent: [Link]['user-agent'], ip: [Link] },
'Request completed'); }); next(); });
✅BEST PRACTICE:
Always generate a unique X-Request-ID (correlation ID) for each incoming request and propagate
it through all downstream service calls. This allows you to trace a single user request across dozens
of microservices and log entries, dramatically reducing debugging time.
Chapter 16: Performance & Caching
16.1 Caching Strategies
Layer Technology TTL Best For
Client-side Browser cache (Cache-Control Minutes to hours Static responses, user-specific
headers) data
CDN CloudFront, Cloudflare, Akamai Seconds to hours Public data, geographic
distribution
API Kong, NGINX, AWS API GW Seconds to Frequently-requested
Gateway minutes endpoints
Application Redis, Memcached Seconds to hours Computed results, DB query
results
Database Query cache, materialized Varies Expensive queries,
views aggregations
Redis Caching Pattern — Cache-Aside
JAVASCRIPT
const Redis = require('ioredis'); const redis = new Redis(); async function
getUserWithCache(userId) { const cacheKey = `user:${userId}`; //
1. Try cache first const cached = await [Link](cacheKey); if
(cached) { return [Link](cached); // Cache HIT } //
2. Cache MISS — fetch from database const user = await
[Link](userId); if (user) { // 3. Store in cache
with TTL await [Link](cacheKey, [Link](user), 'EX', 3600);
// 1 hour } return user; } // Cache invalidation on update
async function updateUser(userId, updates) { const user = await
[Link](userId, updates); // Invalidate cache
await [Link](`user:${userId}`); return user; }
16.2 HTTP Caching Headers
JAVASCRIPT
// Public data — cacheable by CDN and browser [Link]('/api/v1/products',
(req, res) => { [Link]('Cache-Control', 'public, max-age=300, s-
maxage=600'); [Link]('Vary', 'Accept-Encoding'); [Link](products);
}); // Private data — cacheable by browser only [Link]('/api/v1/users/me',
authenticate, (req, res) => { [Link]('Cache-Control', 'private, max-
age=60'); [Link]([Link]); }); // Never cache — sensitive/dynamic
data [Link]('/api/v1/orders/pending', authenticate, (req, res) => {
[Link]('Cache-Control', 'no-store'); [Link](pendingOrders); });
TIP:
Use stale-while-revalidate for API responses that can tolerate slightly stale data. The
directive Cache-Control: public, max-age=60, stale-while-revalidate=300 means:
serve from cache for 60 seconds, then for the next 300 seconds serve stale data while revalidating in
the background. The user never waits for the slow backend.
Chapter 17: Building APIs — Projects
This chapter contains four complete, production-quality API projects. Each builds on the concepts from
previous chapters and introduces new skills.
Project 1: RESTful Task Management API
([Link]/Express)
Architecture Overview
Component Technology
Runtime [Link] 20 + Express 4
Database MongoDB + Mongoose ODM
Component Technology
Authentication JWT (RS256) + Refresh Tokens
Validation Joi / Zod
Testing Jest + Supertest
Documentation OpenAPI 3.1 + Swagger UI
Containerization Docker + Docker Compose
Features
● User registration and login with JWT + refresh tokens
● Role-based access control (admin, manager, user)
● Full CRUD on tasks with categories and tags
● Pagination (cursor-based), filtering, sorting, full-text search
● File upload for task attachments (S3-compatible)
● Rate limiting (token bucket with Redis)
● Structured JSON logging with correlation IDs
● Health check endpoint
● Comprehensive test suite (80%+ coverage)
Database Schema
JAVASCRIPT — Mongoose Models
// models/[Link] const userSchema = new [Link]({ name: { type:
String, required: true, trim: true, maxlength: 100 }, email: { type:
String, required: true, unique: true, lowercase: true }, password: {
type: String, required: true, minlength: 8 }, role: { type: String, enum:
['admin', 'manager', 'user'], default: 'user' }, refreshTokenVersion: {
type: Number, default: 0 }, isActive: { type: Boolean, default: true } },
{ timestamps: true }); // models/[Link] const taskSchema = new
[Link]({ title: { type: String, required: true, maxlength: 200
}, description: { type: String, maxlength: 5000 }, status: {
type: String, enum: ['todo', 'in_progress', 'review', 'done',
'cancelled'], default: 'todo' }, priority: { type: String,
enum: ['low', 'medium', 'high', 'urgent'], default: 'medium' }, dueDate:
Date, tags: [{ type: String, lowercase: true, trim: true }],
category: { type: [Link], ref: 'Category' },
assignee: { type: [Link], ref: 'User' },
createdBy: { type: [Link], ref: 'User', required:
true }, attachments: [{ filename: String, url: String,
mimeType: String, size: Number, uploadedAt: { type: Date,
default: [Link] } }] }, { timestamps: true }); [Link]({
title: 'text', description: 'text' }); [Link]({ createdBy: 1,
status: 1 }); [Link]({ dueDate: 1 });
Docker Compose
YAML — [Link]
version: '3.8' services: api: build: . ports: - "3000:3000"
environment: - NODE_ENV=production -
MONGODB_URI=mongodb://mongo:27017/taskapi -
REDIS_URL=redis://redis:6379 -
JWT_PRIVATE_KEY_PATH=/run/secrets/jwt_private -
JWT_PUBLIC_KEY_PATH=/run/secrets/jwt_public depends_on: - mongo
- redis mongo: image: mongo:7 volumes: - mongo_data:/data/db
ports: - "27017:27017" redis: image: redis:7-alpine ports:
- "6379:6379" volumes: mongo_data:
Project 2: E-Commerce GraphQL API (Python/FastAPI)
Architecture Overview
Component Technology
Runtime Python 3.12 + FastAPI
GraphQL Strawberry GraphQL
Database PostgreSQL + SQLAlchemy
Cache Redis
Testing pytest + httpx
GraphQL Schema
PYTHON
import strawberry from typing import Optional from datetime import datetime
@[Link] class Product: id: int name: str description:
Optional[str] price: float stock: int category: 'Category'
images: list[str] created_at: datetime @[Link] class CartItem:
product: Product quantity: int subtotal: float @[Link]
class Order: id: int items: list['OrderItem'] total_amount: float
status: str created_at: datetime @[Link] class Query:
@[Link] async def products( self, category_id:
Optional[int] = None, search: Optional[str] = None,
min_price: Optional[float] = None, max_price: Optional[float] = None,
limit: int = 25, offset: int = 0, ) -> list[Product]:
"""Search and filter products.""" return await [Link](
category_id=category_id, search=search, min_price=min_price,
max_price=max_price, limit=limit, offset=offset )
@[Link] class Mutation: @[Link] async def
add_to_cart(self, product_id: int, quantity: int = 1) -> CartItem:
"""Add a product to the shopping cart.""" return await
CartService.add_item(product_id, quantity) @[Link]
async def place_order(self, payment_method_id: str) -> Order:
"""Convert cart to an order and process payment.""" return await
OrderService.create_from_cart(payment_method_id)
Project 3: Real-Time Chat API (Go/Gin + gRPC)
Architecture Overview
Component Technology
Runtime Go 1.22
HTTP API Gin framework
Real-time gRPC bidirectional streaming
Pub/Sub Redis Streams
Database PostgreSQL + Redis
Proto Definition
PROTOBUF
syntax = "proto3"; package chat; service ChatService { // Join a room
and receive messages in real-time rpc JoinRoom (stream ClientMessage)
returns (stream ServerMessage); // Get room history rpc
GetHistory (GetHistoryRequest) returns (GetHistoryResponse); } message
ClientMessage { oneof payload { JoinRequest join = 1;
TextMessage text = 2; TypingIndicator typing = 3; } } message
ServerMessage { oneof payload { TextMessage message = 1;
UserJoined user_joined = 2; UserLeft user_left = 3;
TypingIndicator typing = 4; } } message TextMessage { string id = 1;
string room_id = 2; string user_id = 3; string content = 4; int64
timestamp = 5; }
Project 4: Microservices API Platform (Java/Spring
Boot)
Architecture
Service Port Database Purpose
API Gateway 8080 — Routing, auth, rate limiting
User Service 8081 PostgreSQL User management, authentication
Product Service 8082 MongoDB Product catalog, search
Order Service 8083 PostgreSQL Order management, saga orchestration
Config Server 8888 Git Centralized configuration
Eureka Server 8761 — Service discovery
Spring Cloud Gateway Configuration
YAML — [Link]
spring: cloud: gateway: routes: - id: user-service
uri: lb://user-service predicates: -
Path=/api/v1/users/**, /api/v1/auth/** filters: -
RewritePath=/api/v1/(?<segment>.*), /${segment} - name:
CircuitBreaker args: name: userServiceCB
fallbackUri: forward:/fallback/users - name: RequestRateLimiter
args: [Link]: 10
[Link]: 20 - id: product-
service uri: lb://product-service predicates:
- Path=/api/v1/products/** filters: -
RewritePath=/api/v1/(?<segment>.*), /${segment} - id: order-service
uri: lb://order-service predicates: -
Path=/api/v1/orders/** filters: -
RewritePath=/api/v1/(?<segment>.*), /${segment} - name:
CircuitBreaker args: name: orderServiceCB
TIP:
When building microservices, start with a monolith and extract services as needed. The "monolith
first" approach (advocated by Martin Fowler and Sam Newman) lets you discover the right service
boundaries through experience rather than guessing upfront. Premature decomposition into
microservices is one of the most expensive architectural mistakes.
Chapter 18: Advanced Topics
18.1 Event-Driven Architecture
Event Sourcing
Instead of storing the current state, event sourcing stores a sequence of state-changing events. The
current state is derived by replaying all events. This provides a complete audit trail and enables
temporal queries.
JAVASCRIPT — Event Sourcing Example
// Events (immutable facts) const events = [ { type: 'OrderCreated',
data: { orderId: '123', items: [...], total: 99.99 } }, { type:
'PaymentReceived', data: { orderId: '123', amount: 99.99 } }, { type:
'OrderShipped', data: { orderId: '123', trackingNumber: 'UPS123' } }, {
type: 'OrderDelivered', data: { orderId: '123', deliveredAt: '2026-04-20' }
}, ]; // Derive current state by replaying events function
deriveOrderState(events) { return [Link]((state, event) => {
switch ([Link]) { case 'OrderCreated': return
{ ...state, ...[Link], status: 'created' }; case
'PaymentReceived': return { ...state, status: 'paid', paidAt:
[Link] }; case 'OrderShipped': return {
...state, status: 'shipped', trackingNumber: [Link] };
case 'OrderDelivered': return { ...state, status: 'delivered'
}; default: return state; } }, {}); }
18.2 Serverless APIs
Platform Runtime Cold Start Max Duration Pricing
AWS Lambda [Link], Python, Java, 100ms–2s 15 min $0.20 per 1M
Go, .NET, Ruby requests + compute
time
Azure [Link], Python, Java, 200ms–3s 10 min $0.20 per 1M
Functions C#, PowerShell (consumption) requests + compute
time
Cloudflare JavaScript/WASM <1ms (V8 30s (free) / 15 min $0.50 per 1M
Workers isolates) (paid) requests
Google Cloud [Link], Python, Java, 100ms–2s 9 min (1st gen) / $0.40 per 1M
Functions Go, .NET, Ruby, PHP 60 min (2nd gen) requests + compute
time
AWS Lambda API Example
JAVASCRIPT
// [Link] — AWS Lambda function for API Gateway export const handler =
async (event) => { const { httpMethod, pathParameters, body,
queryStringParameters } = event; try { switch (httpMethod) {
case 'GET': if (pathParameters?.id) {
const user = await [Link]([Link]);
return response(200, user); } const users =
await [Link](queryStringParameters); return
response(200, users); case 'POST': const newUser
= await [Link]([Link](body)); return
response(201, newUser); default: return
response(405, { error: 'Method not allowed' }); } } catch (error)
{ [Link]('Error:', error); return response(500, {
error: 'Internal server error' }); } }; function response(statusCode,
body) { return { statusCode, headers: {
'Content-Type': 'application/json', 'Access-Control-Allow-
Origin': '*' }, body: [Link](body) }; }
18.3 AI/ML APIs
Serving machine learning models as APIs is a growing pattern. Key considerations include streaming
inference for LLMs, model versioning, A/B testing between model versions, and managing GPU
resources.
✅BEST PRACTICE:
When serving ML models as APIs, use streaming responses (Server-Sent Events) for large language
models to provide progressive output. Implement model versioning so you can run A/B tests
between model versions. Always set timeouts for inference — GPU workloads can hang, and you
don't want to block your API server.
Chapter 19: API Business Models
19.1 API Monetization Models
Model Description Examples Revenue Potential
Freemium Free tier with limited usage; paid Google Maps, Medium (requires
tiers for more OpenWeatherMap volume)
Model Description Examples Revenue Potential
Pay-per-call Charge per API request (metered AWS services, Twilio High (scales with
billing) usage)
Subscription Fixed monthly fee for a tier of Stripe, SendGrid High (predictable
access revenue)
Revenue Take a percentage of transactions Stripe (2.9% + 30¢), Very High
Sharing processed PayPal
Indirect / API is free; monetized through Facebook Graph API, Indirect (platform
Free ecosystem growth Twitter API value)
Marketplace Third-party APIs sold through RapidAPI, AWS Commission-based
marketplace Marketplace
19.2 Case Study: Stripe's API Business Model
Stripe is widely regarded as having the best API in the industry. Their success is built on:
● Developer-first: Exceptional documentation, interactive tutorials, clear error messages
● Revenue sharing model: 2.9% + 30¢ per transaction — aligned incentives (they earn when you
earn)
● API design: Consistent naming, idempotency keys, comprehensive webhooks, expandable
responses
● SDKs: Official libraries in 7+ languages, actively maintained
● Versioning: Dated API versions (e.g., 2024-04-10), backward compatibility for years
Chapter 20: Case Studies & System Design
20.1 System Design Interview Framework
83. Clarify Requirements (5 min): Functional requirements, non-functional requirements, scale
estimates
84. High-Level Design (10 min): Core components, data flow, API endpoints
85. Detailed Design (15 min): Database schema, API contracts, algorithms
86. Scalability & Trade-offs (10 min): Bottlenecks, scaling strategies, trade-offs
20.2 Case Study: Design Twitter/X API
Requirements
● Functional: Post tweets, follow users, timeline (home + user), search, like/retweet, notifications
● Non-functional: 500M daily active users, 600K tweets/second (read), timeline in <200ms
Core API Endpoints
REST API DESIGN
# Tweets POST /api/v1/tweets # Create tweet GET
/api/v1/tweets/:id # Get tweet DELETE /api/v1/tweets/:id
# Delete tweet POST /api/v1/tweets/:id/like # Like tweet DELETE
/api/v1/tweets/:id/like # Unlike tweet POST
/api/v1/tweets/:id/retweet # Retweet # Timeline GET
/api/v1/timeline/home # Home timeline (followed users) GET
/api/v1/timeline/user/:userId # User's tweets # Users POST
/api/v1/users/:id/follow # Follow user DELETE
/api/v1/users/:id/follow # Unfollow user GET
/api/v1/users/:id/followers # Get followers GET
/api/v1/users/:id/following # Get following # Search GET
/api/v1/search?q=term&type=tweets # Search tweets, users, hashtags
Timeline Generation Strategy
Approach How It Works Pros Cons
Fan-out on When user posts, immediately Fast reads Slow writes for celebrity
Write push tweet to all followers' (<50ms), simple users (millions of followers),
timeline caches read path storage overhead
Fan-out on When user opens timeline, pull Simple writes, Slow reads (must query many
Read tweets from all followed users no storage users), high compute
and merge overhead
Hybrid Fan-out on write for most Balances Complex, requires user
(Twitter's users; fan-out on read for read/write classification
approach) celebrities (>5K followers) performance
20.3 Case Study: Design Stripe Payment API
Key Design Decisions
● Idempotency: Every payment request requires an Idempotency-Key header. If a network
failure causes a retry, the same payment is not processed twice.
● Webhooks: Payment events (succeeded, failed, refunded) are delivered via webhooks with
HMAC signature verification.
● PCI Compliance: Card numbers never touch the merchant's server. [Link]/Elements tokenize
card data in the browser, and the server only receives a token.
● Two-phase payment: Authorize first, then capture later (enables holds for hotels, car rentals).
20.4 Case Study: Design Uber/Lyft API
Core Challenges
● Real-time location tracking: WebSocket or gRPC streaming for driver/rider position updates
● Matching algorithm: Match riders with nearby available drivers based on ETA, not distance
● Surge pricing: Dynamic pricing API based on supply-demand ratio in geographic cells
● Geospatial queries: Use geohashing (S2 cells) for efficient nearby driver lookups
20.5 Case Study: Design Netflix API
API Architecture
● Zuul Gateway: Netflix's custom API gateway handling 50B+ requests/day
● Backend for Frontend (BFF): Separate API layers for web, mobile, TV (each device has different
capabilities)
● Personalization API: ML-powered recommendations served through a real-time inference API
● Streaming API: Adaptive bitrate streaming with manifest files (DASH/HLS) served through CDN
TIP:
In system design interviews, always start with a clear statement of the scale: "We need to handle
10K requests per second for timeline reads." Then work backward from the performance
requirements to justify your architecture decisions. Interviewers want to see that you can reason
about trade-offs at scale.
Appendix A: 100+ Corporate Interview
Questions
A.1 API Fundamentals (20 Questions)
Q1. What is an API, and why are APIs important in modern software development?
Model Answer: An API (Application Programming Interface) is a set of defined rules and protocols that
allows different software applications to communicate with each other. APIs are important because they
enable modularity, reusability, and interoperability. They allow teams to build systems independently
(frontend/backend separation), enable third-party integrations (Stripe for payments, Twilio for
messaging), and power the modern cloud-native architecture where distributed services communicate
through well-defined interfaces.
What Interviewers Look For:
Clear definition, real-world examples, understanding of why APIs matter for business (not just
technical). Mention of decoupling, scalability, and ecosystem value.
Q2. Explain the difference between REST and SOAP.
Model Answer: REST is an architectural style that uses HTTP methods and JSON for lightweight,
stateless communication. SOAP is a protocol with strict standards using XML, WSDL, and WS-*
specifications. REST is simpler, faster, and more widely adopted for web/mobile APIs. SOAP is preferred
in enterprise environments requiring formal contracts, WS-Security, and reliable messaging (banking,
healthcare). REST uses HTTP status codes for errors; SOAP uses XML fault elements. REST is cacheable by
default; SOAP is not.
What Interviewers Look For:
Not just listing differences but explaining when you'd choose each. Understanding that SOAP is still
relevant in specific domains.
Q3. What makes an API "RESTful"?
Model Answer: A RESTful API follows the six constraints defined by Roy Fielding: client-server
separation, statelessness (no session state on server), cacheability (responses define their cache
behavior), uniform interface (resources identified by URIs, manipulated through representations),
layered system (intermediaries like CDNs/load balancers), and optional code-on-demand. Most APIs
claim to be RESTful but only implement Level 2 of the Richardson Maturity Model (proper HTTP
methods with resources). True REST (Level 3) includes HATEOAS.
Q4. What is the difference between PUT and PATCH?
Model Answer: PUT replaces the entire resource with the provided representation. All fields must be
included; omitted fields are set to null/default. PATCH applies a partial update — only the included fields
are modified. PUT is idempotent by definition. PATCH can be idempotent (JSON Merge Patch) or non-
idempotent (if using relative operations like "increment count by 1"). Use PUT when the client has the
complete resource; use PATCH for partial updates.
Q5. Explain HTTP status code categories and give two examples from each.
Model Answer: 1xx Informational (100 Continue, 101 Switching Protocols), 2xx Success (200 OK, 201
Created), 3xx Redirection (301 Moved Permanently, 304 Not Modified), 4xx Client Errors (400 Bad
Request, 404 Not Found), 5xx Server Errors (500 Internal Server Error, 503 Service Unavailable). The
status code is the first thing automated systems check — load balancers, monitoring, and client libraries
all depend on correct status codes.
Q6. What is idempotency and why does it matter for APIs?
Q7. How would you design pagination for an API that serves millions of records?
Q8. What is content negotiation in REST APIs?
Q9. Explain the concept of API versioning. What strategies exist?
Q10. What is HATEOAS and why do many APIs choose not to implement it?
Q11. How do WebSockets differ from HTTP? When would you use each?
Q12. What is the difference between synchronous and asynchronous APIs?
Q13. Explain the difference between an API and an SDK.
Q14. What are webhooks and how do they differ from polling?
Q15. What is an API gateway and what problems does it solve?
Q16. Explain the difference between API keys, OAuth tokens, and JWTs.
Q17. What is rate limiting and why is it important?
Q18. How do you handle errors in API design?
Q19. What is the difference between 401 and 403 status codes?
Q20. What tools do you use for API development and testing?
A.2 API Design & Architecture (20 Questions)
Q21. How would you design a REST API for a social media platform?
Model Answer: I'd start by identifying the core resources: Users, Posts, Comments, Likes, Follows,
Notifications. Each resource gets standard CRUD endpoints. For the timeline, I'd use a dedicated
endpoint (GET /timeline/home) with cursor-based pagination. Relationships are expressed through sub-
resources (GET /users/:id/posts). I'd use query parameters for filtering and sorting. Authentication
would be JWT-based with OAuth 2.0 for third-party access. Real-time features (notifications, typing
indicators) would use WebSocket connections. Rate limiting per user and per API key.
What Interviewers Look For:
Systematic approach to resource identification, proper REST conventions, consideration of
performance (pagination), security (auth), and real-time requirements.
Q22. How do you handle breaking changes in an API?
Q23. Explain the API-first design approach.
Q24. How would you design an API for a multi-tenant SaaS application?
Q25. What is the Backend for Frontend (BFF) pattern?
Q26. How do you handle file uploads in a REST API?
Q27. Explain the difference between GraphQL and REST. When would you choose each?
Q28. What is gRPC and when is it preferred over REST?
Q29. How would you design an API for a payment processing system?
Q30. What is the Saga pattern in microservices?
Q31. How do you handle partial failures in distributed APIs?
Q32. Explain the circuit breaker pattern.
Q33. How do you design APIs for backward compatibility?
Q34. What is an OpenAPI specification and how do you use it?
Q35. How do you handle long-running operations in an API?
Q36. Explain the event-driven architecture pattern for APIs.
Q37. What are the trade-offs between monolith and microservice APIs?
Q38. How do you design an API that needs to support both mobile and web clients?
Q39. What is API composition and when do you need it?
Q40. How do you handle cross-cutting concerns in a microservices API?
A.3 Security & Authentication (15 Questions)
Q41. Explain OAuth 2.0 Authorization Code flow with PKCE.
Model Answer: The flow proceeds as follows: (1) Client generates a random code_verifier and derives a
code_challenge using SHA-256. (2) Client redirects user to the authorization server with the
code_challenge. (3) User authenticates and consents. (4) Authorization server redirects back with an
authorization code. (5) Client exchanges the code + code_verifier for tokens. (6) Authorization server
verifies the code_verifier matches the original code_challenge. PKCE prevents authorization code
interception attacks — even if an attacker captures the code, they cannot exchange it without the
code_verifier.
What Interviewers Look For:
Complete understanding of the flow, why PKCE exists (security), and awareness that it's now
required for all clients (not just public clients) per OAuth 2.1.
Q42. How do you securely store and transmit API keys?
Q43. Explain JWT structure and security considerations.
Q44. What is the OWASP API Security Top 10?
Q45. How do you prevent BOLA (Broken Object Level Authorization)?
Q46. Explain mutual TLS (mTLS) and when you'd use it.
Q47. How do you handle CORS in API development?
Q48. What is token revocation and how do you implement it with JWTs?
Q49. How do you prevent SQL injection in APIs?
Q50. What is the difference between RBAC and ABAC?
Q51. How do you implement API rate limiting to prevent DDoS?
Q52. What security headers should every API response include?
Q53. How do you handle sensitive data (PII) in API responses?
Q54. What is SSRF and how do you prevent it in APIs?
Q55. How do you implement API key rotation without downtime?
A.4 Performance & Scalability (15 Questions)
Q56. How would you optimize a slow API endpoint?
Q57. Explain caching strategies for APIs.
Q58. How does HTTP/2 improve API performance?
Q59. What is connection pooling and why does it matter?
Q60. How do you handle the N+1 query problem?
Q61. Explain cursor-based pagination vs offset-based.
Q62. How do you implement cache invalidation?
Q63. What is the difference between horizontal and vertical scaling for APIs?
Q64. How do you handle thundering herd problems?
Q65. What load testing tools and strategies do you use?
Q66. How would you design an API for global distribution?
Q67. Explain database indexing strategies for API performance.
Q68. What is ETags and how do they improve API performance?
Q69. How do you handle large response payloads?
Q70. Explain async processing patterns for APIs (queues, workers).
A.5 System Design (20 Questions)
Q71. Design a URL shortening service API (like [Link]).
Q72. Design a real-time notification system API.
Q73. Design a file storage and sharing API (like Dropbox).
Q74. Design a chat messaging API (like Slack).
Q75. Design an e-commerce product search API.
Q76. Design a ride-sharing API (like Uber).
Q77. Design a social media feed/timeline API (like Twitter).
Q78. Design a video streaming API (like Netflix).
Q79. Design a payment processing API (like Stripe).
Q80. Design a booking/reservation API (like Airbnb).
Q81–Q90. Additional system design scenarios (collaborative editing, IoT telemetry, API analytics
platform, food delivery, rate limiting service, content moderation, recommendation engine, multi-region
API deployment, API marketplace, event ticketing).
A.6 Behavioral & Scenario-Based (10 Questions)
Q91. You discover that your API has been returning incorrect data for 2 hours. What do you do?
Model Answer: First, assess the impact: which endpoints, how many users affected, what data was
incorrect. Communicate immediately with stakeholders — post in the incident channel, notify affected
teams. Fix the root cause as the priority — deploy a hotfix or rollback if possible. Once fixed, assess the
data damage: do we need to reprocess or notify affected users? Write a post-mortem covering timeline,
root cause, impact, what we learned, and action items to prevent recurrence. Improve
monitoring/alerting to catch this faster next time.
What Interviewers Look For:
Structured incident response thinking, emphasis on communication, and learning from failures
(post-mortem culture).
Q92. A partner complains your API is too slow. How do you investigate?
Q93. Your team wants to rewrite the API from scratch. How do you evaluate this decision?
Q94. How do you handle a situation where two teams disagree on API design?
Q95. Describe a time you improved API performance significantly.
Q96. How would you migrate from a monolith to microservices APIs?
Q97. A critical API dependency is experiencing an outage. What do you do?
Q98. How do you ensure API quality when shipping quickly?
Q99. How do you handle a security vulnerability discovered in production?
Q100. Describe your approach to API documentation.
Appendix B:Glossary of API Terms
Term Definition
ABAC Attribute-Based Access Control — authorization based on attributes of the user,
resource, and environment.
API Gateway A server that acts as the single entry point for API requests, handling routing,
auth, rate limiting, and monitoring.
API Key A unique string identifier used to authenticate and identify an API consumer.
Term Definition
AsyncAPI A specification for documenting event-driven and asynchronous APIs,
analogous to OpenAPI for REST.
Authentication The process of verifying the identity of a client or user ("Who are you?").
(AuthN)
Authorization The process of determining what actions an authenticated user is allowed to
(AuthZ) perform ("What can you do?").
Base URL The root URL of an API upon which all endpoint paths are built (e.g.,
[Link]
Bearer Token An access token sent in the Authorization header to authenticate API requests.
BFF Backend for Frontend — a dedicated API layer tailored for a specific client type
(web, mobile, TV).
BOLA Broken Object Level Authorization — a vulnerability where users can access
other users' resources by manipulating IDs.
Cache-Control An HTTP header that specifies caching directives for requests and responses.
Callback URL A URL that a server sends data to when an event occurs (used by webhooks and
OAuth).
CDN Content Delivery Network — a geographically distributed network of servers
that caches and serves content closer to users.
Circuit Breaker A resilience pattern that stops calling a failing service after a threshold, allowing
it time to recover.
Client Any software that makes requests to an API (browser, mobile app, another
server).
Consumer A developer, application, or organization that uses an API.
Content The mechanism by which client and server agree on the data format (via Accept
Negotiation and Content-Type headers).
Contract Testing Testing that verifies the API implementation matches the API
specification/contract.
CORS Cross-Origin Resource Sharing — a browser security mechanism that controls
which domains can access an API.
CRUD Create, Read, Update, Delete — the four basic operations on data, mapped to
POST, GET, PUT/PATCH, DELETE.
CQRS Command Query Responsibility Segregation — separating read and write
models for performance and scalability.
Cursor An opaque token used in cursor-based pagination to identify a position in a
dataset.
Term Definition
DataLoader A utility for batching and caching data lookups, commonly used in GraphQL to
solve the N+1 problem.
Deprecation The process of marking an API version or feature as outdated, with a planned
removal date.
DNS Domain Name System — resolves human-readable domain names to IP
addresses.
DPoP Demonstrating Proof of Possession — a mechanism to bind access tokens to a
specific client key pair.
Endpoint A specific URL path where an API resource can be accessed (e.g.,
/api/v1/users).
Error Budget The allowed amount of unreliability based on SLO targets (e.g., if SLO is 99.9%,
error budget is 0.1%).
ETag Entity Tag — an HTTP header containing a version identifier for a resource,
used for caching and concurrency control.
Event Sourcing A pattern where state changes are stored as a sequence of immutable events
rather than overwriting current state.
Fan-out The process of distributing a message or data to multiple recipients or services.
GraphQL A query language for APIs that lets clients request exactly the data they need
through a strongly typed schema.
gRPC Google Remote Procedure Call — a high-performance RPC framework using
Protocol Buffers and HTTP/2.
HAL Hypertext Application Language — a JSON format for representing hypermedia
links in API responses.
HATEOAS Hypermedia as the Engine of Application State — REST principle where
responses include links to related resources.
Health Check An endpoint (typically /health) that reports the operational status of a
service.
HMAC Hash-based Message Authentication Code — used to verify message integrity
and authenticity.
HTTP Hypertext Transfer Protocol — the application-layer protocol used for web and
API communication.
Idempotency The property of an operation where performing it multiple times produces the
same result as performing it once.
Idempotency Key A unique client-generated key sent with non-idempotent requests to enable
safe retries.
Term Definition
Introspection In GraphQL, the ability to query the schema itself to discover available types,
fields, and operations.
JSON JavaScript Object Notation — a lightweight data-interchange format widely
used in API payloads.
JSON Schema A specification for defining the structure and validation rules of JSON data.
JWT JSON Web Token — a compact, URL-safe token format containing signed claims
for authentication.
Latency The time elapsed between sending a request and receiving a response, often
measured at p50, p95, p99.
Load Balancer A component that distributes incoming traffic across multiple server instances.
Middleware Software that intercepts and processes requests/responses in a pipeline (auth,
logging, validation).
Mutation In GraphQL, an operation that modifies server-side data (analogous to
POST/PUT/DELETE in REST).
mTLS Mutual TLS — both client and server present certificates to authenticate each
other.
N+1 Problem A performance issue where N additional database queries are made for N items
in a collection.
OAuth 2.0 An authorization framework that enables third-party applications to access
resources on behalf of a user.
OIDC OpenID Connect — an identity layer on top of OAuth 2.0 that provides user
authentication.
OpenAPI A specification (formerly Swagger) for describing REST API contracts in YAML or
JSON format.
OpenTelemetry An open-source observability framework for generating, collecting, and
exporting telemetry data.
Pagination Dividing a large dataset into smaller pages to reduce response size and improve
performance.
Payload The data sent in the body of an HTTP request or response.
PKCE Proof Key for Code Exchange — an OAuth 2.0 extension that prevents
authorization code interception attacks.
Preflight Request An HTTP OPTIONS request sent by the browser before a cross-origin request to
check CORS permissions.
Protocol Buffers Google's binary serialization format used by gRPC — more compact and faster
than JSON.
Term Definition
Provider The server-side system that hosts and serves the API.
Query In GraphQL, an operation that reads data without modifying it (analogous to
GET in REST).
Rate Limiting Restricting the number of API requests a client can make within a time window.
RBAC Role-Based Access Control — authorization based on predefined roles assigned
to users.
Resolver In GraphQL, a function that fetches the data for a specific field in the schema.
Resource An entity or object that an API manages, identified by a URI (e.g., user, product,
order).
REST Representational State Transfer — an architectural style for distributed systems
using HTTP.
RFC Request for Comments — documents published by the IETF defining internet
standards and protocols.
Saga Pattern A pattern for managing distributed transactions across microservices using a
sequence of local transactions.
Schema A formal definition of data structure, types, and validation rules for an API.
SDK Software Development Kit — pre-built libraries that wrap API calls in a
language-specific interface.
Serialization The process of converting data structures into a transmittable format (JSON,
XML, Protobuf).
Service Mesh Infrastructure layer handling service-to-service communication (mTLS, traffic
management, observability).
SLA Service Level Agreement — a contractual commitment for service performance
with consequences for breach.
SLI Service Level Indicator — a quantitative metric measuring service performance
(latency, error rate).
SLO Service Level Objective — a target value for an SLI that the team commits to
meeting.
SOAP Simple Object Access Protocol — an XML-based messaging protocol with formal
WS-* standards.
SSE Server-Sent Events — a standard for one-way server-to-client streaming over
HTTP.
Stateless A design principle where the server retains no session state between requests.
Subscription In GraphQL, a mechanism for receiving real-time updates when data changes.
Term Definition
Sunset The planned removal of a deprecated API version, communicated via the
Sunset HTTP header (RFC 8594).
Swagger The original name for OpenAPI; now refers to tools (Swagger UI, Swagger
Editor) around the specification.
Throttling Slowing down or queuing excess requests rather than rejecting them outright.
TLS Transport Layer Security — cryptographic protocol that provides encryption for
data in transit (HTTPS).
Token Bucket A rate limiting algorithm where tokens are added at a fixed rate and consumed
by each request.
Trace A record of a request's journey across multiple services, used for debugging
distributed systems.
URI Uniform Resource Identifier — a string that identifies a resource (includes URLs
and URNs).
Webhook A callback mechanism where a server pushes data to a client's URL when a
specific event occurs.
WebSocket A protocol providing full-duplex, bidirectional communication over a single TCP
connection.
WSDL Web Services Description Language — XML document describing a SOAP web
service's interface.
Appendix C: CLI Cheatsheets
C.1 curl Commands
Action Command
GET request curl [Link]
GET with headers curl -H "Authorization: Bearer TOKEN"
[Link]
POST JSON curl -X POST -H "Content-Type: application/json" -d
'{"name":"Sasank"}' [Link]
Action Command
PUT request curl -X PUT -H "Content-Type: application/json" -d
'{"name":"Updated"}' [Link]
PATCH request curl -X PATCH -H "Content-Type: application/json" -d
'{"email":"new@[Link]"}' [Link]
DELETE request curl -X DELETE [Link]
Show response curl -i [Link]
headers
Show only headers curl -I [Link]
Verbose output curl -v [Link]
Follow redirects curl -L [Link]
Upload file curl -X POST -F "file=@[Link]"
[Link]
Set timeout curl --connect-timeout 5 --max-time 30
[Link]
Save response to curl -o [Link] [Link]
file
Basic curl -u username:password [Link]
authentication
Pretty print JSON curl -s [Link] | python -m
[Link]
C.2 httpie Commands
Action Command
GET request http GET [Link]
POST JSON http POST [Link] name=Sasank
email=s@[Link]
PUT request http PUT [Link]
name=Updated
DELETE request http DELETE [Link]
Custom header http GET [Link]
Authorization:"Bearer TOKEN"
Query parameters http GET [Link] page==2
per_page==25
Action Command
Upload file http -f POST [Link]
file@[Link]
Download file http --download
[Link]
Show only headers http --headers GET [Link]
Session (persist cookies) http --session=mysession POST
[Link]
C.3 Docker CLI for API Deployment
Action Command
Build image docker build -t my-api:1.0 .
Run container docker run -d -p 3000:3000 --name api my-api:1.0
Run with env vars docker run -d -p 3000:3000 -e DB_URL=... my-api:1.0
View logs docker logs -f api
Stop container docker stop api
Remove container docker rm api
Compose up docker compose up -d
Compose down docker compose down -v
List containers docker ps
Exec into container docker exec -it api /bin/sh
Push to registry docker push [Link]/my-api:1.0
C.4 kubectl for API Deployment
Action Command
Apply manifests kubectl apply -f k8s/
Get pods kubectl get pods -n api-namespace
Get services kubectl get svc -n api-namespace
Action Command
View pod logs kubectl logs -f deployment/api-server -n api-namespace
Describe pod kubectl describe pod api-server-abc123 -n api-namespace
Port forward kubectl port-forward svc/api-server 3000:3000 -n api-
namespace
Scale deployment kubectl scale deployment api-server --replicas=5
Rolling update kubectl set image deployment/api-server api=my-api:2.0
Rollback kubectl rollout undo deployment/api-server
Get config maps kubectl get configmap -n api-namespace
Appendix D: OpenAPI/Swagger Complete
Examples
D.1 Pet Store API (OpenAPI 3.1)
YAML
openapi: 3.1.0 info: title: Pet Store API version: 1.0.0 description: A
sample Pet Store API demonstrating OpenAPI 3.1 features. contact: name:
API Support email: support@[Link] license: name:
Apache 2.0 servers: - url: [Link]
description: Production - url: [Link]
description: Staging paths: /pets: get: operationId: listPets
summary: List all pets tags: [Pets] parameters: - name:
species in: query schema: type: string
enum: [dog, cat, bird, fish] - name: limit in: query
schema: type: integer default: 25
maximum: 100 - name: cursor in: query schema:
type: string responses: '200': description: A
paginated list of pets content: application/json:
schema: type: object properties:
data: type: array items:
$ref: '#/components/schemas/Pet' next_cursor:
type: string nullable: true post: operationId:
createPet summary: Create a pet tags: [Pets] security:
- bearerAuth: [] requestBody: required: true content:
application/json: schema: $ref:
'#/components/schemas/CreatePetRequest' responses: '201':
description: Pet created headers: Location:
schema: type: string content:
application/json: schema: $ref:
'#/components/schemas/Pet' '422': description: Validation
error content: application/json: schema:
$ref: '#/components/schemas/Error' /pets/{petId}: get:
operationId: getPet summary: Get a pet by ID tags: [Pets]
parameters: - name: petId in: path required: true
schema: type: integer responses: '200':
description: Pet details content: application/json:
schema: $ref: '#/components/schemas/Pet' '404':
description: Pet not found components: schemas: Pet: type:
object required: [id, name, species] properties: id:
type: integer name: type: string species:
type: string enum: [dog, cat, bird, fish] breed:
type: string age: type: integer adopted:
type: boolean default: false created_at: type:
string format: date-time CreatePetRequest: type: object
required: [name, species] properties: name: type:
string minLength: 1 maxLength: 100 species:
type: string enum: [dog, cat, bird, fish] breed:
type: string age: type: integer minimum: 0
Error: type: object properties: type: type:
string title: type: string status: type:
integer detail: type: string errors:
type: array items: type: object properties:
field: type: string message:
type: string securitySchemes: bearerAuth: type: http
scheme: bearer bearerFormat: JWT
Appendix E: Protocol Buffers Examples
E.1 Complete Proto File — User Service
PROTOBUF
syntax = "proto3"; package userservice.v1; option go_package =
"[Link]/myapp/proto/userservice/v1"; option java_package =
"[Link].v1"; import "google/protobuf/[Link]";
import "google/protobuf/field_mask.proto"; // User represents a registered
user in the system. message User { int64 id = 1; string name = 2;
string email = 3; UserRole role = 4; bool is_active = 5;
[Link] created_at = 6; [Link]
updated_at = 7; map<string, string> metadata = 8; } enum UserRole {
USER_ROLE_UNSPECIFIED = 0; USER_ROLE_USER = 1; USER_ROLE_ADMIN = 2;
USER_ROLE_MANAGER = 3; } // --- Requests and Responses --- message
CreateUserRequest { string name = 1; string email = 2; string
password = 3; UserRole role = 4; } message GetUserRequest { int64 id
= 1; } message UpdateUserRequest { int64 id = 1; User user = 2;
[Link] update_mask = 3; } message DeleteUserRequest {
int64 id = 1; } message ListUsersRequest { int32 page_size = 1;
string page_token = 2; string filter = 3; // e.g., "role=ADMIN"
string order_by = 4; // e.g., "created_at desc" } message ListUsersResponse
{ repeated User users = 1; string next_page_token = 2; int32
total_count = 3; } // --- Service Definition --- service UserService {
rpc CreateUser (CreateUserRequest) returns (User); rpc GetUser
(GetUserRequest) returns (User); rpc UpdateUser (UpdateUserRequest)
returns (User); rpc DeleteUser (DeleteUserRequest) returns
([Link]); rpc ListUsers (ListUsersRequest) returns
(ListUsersResponse); }
E.2 Proto Best Practices
● Use field numbers 1–15 for frequently accessed fields (1-byte encoding)
● Never reuse or reassign field numbers after deployment
● Use reserved keyword for removed fields to prevent accidental reuse
● Prefix enum values with the enum name (e.g., USER_ROLE_ADMIN)
● Always include an UNSPECIFIED = 0 value for enums
● Use [Link] for partial updates
● Use [Link] for datetime fields
● Version your packages (e.g., userservice.v1)
Appendix F: Security Checklist
# Category Check Item Priority
1 Transport All traffic uses HTTPS (TLS 1.2+) Critical
2 Transport HSTS header enabled with long max-age High
3 Transport TLS certificate is valid and auto-renewed Critical
4 Authentication Passwords hashed with bcrypt/argon2 (never Critical
MD5/SHA1)
5 Authentication JWT tokens have short expiration (5–15 min) High
6 Authentication Refresh tokens are stored securely and can be revoked High
7 Authentication API keys can be rotated without downtime Medium
# Category Check Item Priority
8 Authentication Failed login rate limiting (e.g., 5 attempts/minute) High
9 Authentication Multi-factor authentication available for admin accounts High
10 Authorization Object-level authorization on every endpoint (BOLA Critical
prevention)
11 Authorization Function-level authorization (BFLA prevention) Critical
12 Authorization Role-based access control implemented and tested High
13 Authorization Mass assignment protection (allowlist request fields) High
14 Input All input validated (type, length, format, range) Critical
15 Input Parameterized queries (prevent SQL/NoSQL injection) Critical
16 Input Request body size limits enforced High
17 Input File upload type and size validation High
18 Input URL parameters sanitized (prevent path traversal) High
19 Output Sensitive data excluded from responses (passwords, Critical
internal IDs)
20 Output Stack traces and debug info disabled in production Critical
21 Output PII data minimized in responses High
22 Output Response headers don't leak server technology Medium
23 Headers X-Content-Type-Options: nosniff High
24 Headers X-Frame-Options: DENY Medium
25 Headers Content-Security-Policy configured Medium
26 Headers Referrer-Policy: strict-origin-when-cross-origin Medium
27 Rate Limiting Rate limiting implemented on all endpoints High
28 Rate Limiting Stricter limits on auth endpoints (login, register) High
29 Rate Limiting 429 response includes Retry-After header Medium
30 CORS Origins explicitly allowlisted (no wildcard with High
credentials)
31 CORS Allowed methods and headers explicitly configured Medium
32 Secrets No secrets in source code or environment variables in Critical
code
# Category Check Item Priority
33 Secrets Secrets stored in vault (AWS SM, Azure KV, HashiCorp High
Vault)
34 Secrets Secrets rotated regularly Medium
35 Logging All authentication events logged (success and failure) High
36 Logging All authorization failures logged High
37 Logging Sensitive data excluded from logs (passwords, tokens, Critical
PII)
38 Logging Audit trail for data modifications Medium
39 Dependencies Dependencies scanned for known vulnerabilities (npm High
audit, Snyk)
40 Dependencies Dependencies pinned to specific versions Medium
41 Infrastructure API endpoints not exposing debug/admin interfaces in Critical
production
42 Infrastructure Database not accessible from public internet Critical
43 Infrastructure WAF (Web Application Firewall) in place Medium
44 Infrastructure DDoS protection enabled Medium
45 Compliance GDPR: data deletion/export endpoints available High
46 Compliance Data encryption at rest High
47 Compliance Privacy policy and terms of service documented Medium
48 Testing Automated security testing in CI/CD pipeline High
49 Testing Regular penetration testing (at least annually) Medium
50 Testing OWASP API Top 10 reviewed for each endpoint High
Appendix G: Testing Checklist
# Category Test Item
1 Functional All CRUD operations return correct status codes
# Category Test Item
2 Functional GET endpoints return correct data format and structure
3 Functional POST creates resource and returns 201 with Location header
4 Functional PUT replaces the full resource correctly
5 Functional PATCH applies partial updates correctly
6 Functional DELETE removes resource and returns 204
7 Functional Pagination returns correct page size and total count
8 Functional Filtering returns only matching records
9 Functional Sorting returns records in correct order
10 Functional Search returns relevant results
11 Validation Required fields enforced (422 when missing)
12 Validation Field type validation (string, number, email, etc.)
13 Validation Field length/range limits enforced
14 Validation Invalid JSON body returns 400
15 Validation Unsupported Content-Type returns 415
16 Auth Unauthenticated requests return 401
17 Auth Invalid tokens return 401
18 Auth Expired tokens return 401
19 Auth Unauthorized role access returns 403
20 Auth User cannot access other users' resources (BOLA)
21 Error 404 returned for non-existent resources
22 Error 405 returned for unsupported HTTP methods
23 Error 409 returned for conflicts (duplicate data)
24 Error 429 returned when rate limit exceeded
25 Error Error responses follow consistent format (RFC 7807)
26 Error No stack traces or internal details in error responses
27 Performance Response times within SLO targets under normal load
28 Performance API handles expected concurrent user load
29 Performance No memory leaks under sustained load
# Category Test Item
30 Performance Database connection pool properly configured
31 Edge Cases Empty collections return 200 with empty array (not 404)
32 Edge Cases Large payloads handled correctly or rejected with 413
33 Edge Cases Special characters in input handled correctly
34 Edge Cases Concurrent updates handled (optimistic locking)
35 Edge Cases Idempotency keys prevent duplicate operations
36 Integration Database operations succeed with real database
37 Integration External API calls are mocked in tests
38 Integration Webhook delivery tested
39 Contract API responses match OpenAPI specification
40 Contract Consumer contracts verified
Appendix H: CI/CD Pipeline Examples
H.1 GitHub Actions — [Link] API
YAML — .github/workflows/[Link]
name: API CI/CD Pipeline on: push: branches: [main, develop]
pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest
services: mongodb: image: mongo:7 ports:
['27017:27017'] redis: image: redis:7-alpine ports:
['6379:6379'] steps: - uses: actions/checkout@v4 - uses:
actions/setup-node@v4 with: node-version: '20'
cache: 'npm' - run: npm ci - run: npm run lint - run: npm
run test:unit - run: npm run test:integration env:
MONGODB_URI: mongodb://localhost:27017/test REDIS_URL:
redis://localhost:6379 - run: npm run test:coverage - uses:
actions/upload-artifact@v4 with: name: coverage-report
path: coverage/ security: runs-on: ubuntu-latest steps: -
uses: actions/checkout@v4 - run: npm audit --audit-level=high -
uses: aquasecurity/trivy-action@master with: scan-type:
'fs' severity: 'HIGH,CRITICAL' deploy: needs: [test,
security] if: [Link] == 'refs/heads/main' runs-on: ubuntu-latest
steps: - uses: actions/checkout@v4 - uses: docker/login-action@v3
with: registry: [Link] username: ${{ [Link] }}
password: ${{ secrets.GITHUB_TOKEN }} - uses: docker/build-push-
action@v5 with: push: true tags: [Link]/${{
[Link] }}:${{ [Link] }}
H.2 GitHub Actions — Python API
YAML
name: Python API CI on: [push, pull_request] jobs: test: runs-on:
ubuntu-latest services: postgres: image: postgres:16
env: POSTGRES_DB: testdb POSTGRES_USER: test
POSTGRES_PASSWORD: test ports: ['5432:5432'] steps: -
uses: actions/checkout@v4 - uses: actions/setup-python@v5 with:
python-version: '3.12' - run: pip install -r [Link] -
run: ruff check . - run: mypy src/ - run: pytest tests/ -v --
cov=src --cov-report=xml env: DATABASE_URL:
postgresql://test:test@localhost:5432/testdb
Appendix I: Sample API Contracts
I.1 REST API Contract Template
YAML
openapi: 3.1.0 info: title: [Service Name] API version: 1.0.0
description: "[Brief description of what this API does]" contact: name:
[Team Name] email: [team-email@[Link]] servers: - url:
[Link] description: Production - url:
[Link] description: Staging security: -
bearerAuth: [] paths: /[resources]: get: summary: List
[resources] parameters: - $ref:
'#/components/parameters/PageSize' - $ref:
'#/components/parameters/Cursor' responses: '200':
description: Success '401': $ref:
'#/components/responses/Unauthorized' components: parameters:
PageSize: name: page_size in: query schema: type:
integer default: 25 maximum: 100 Cursor: name:
cursor in: query schema: type: string responses:
Unauthorized: description: Authentication required content:
application/json: schema: $ref:
'#/components/schemas/Error' schemas: Error: type: object
properties: type: { type: string } title: { type: string }
status: { type: integer } detail: { type: string }
securitySchemes: bearerAuth: type: http scheme: bearer
bearerFormat: JWT
I.2 AsyncAPI Contract Template
YAML
asyncapi: 2.6.0 info: title: Order Events API version: 1.0.0
description: Asynchronous events for order lifecycle servers: production:
url: kafka://[Link] protocol: kafka channels:
[Link]: publish: summary: Order created event
message: $ref: '#/components/messages/OrderCreated'
[Link]: publish: summary: Order shipped event
message: $ref: '#/components/messages/OrderShipped' components:
messages: OrderCreated: payload: type: object
properties: order_id: type: string
customer_id: type: string items: type:
array total_amount: type: number created_at:
type: string format: date-time OrderShipped: payload:
type: object properties: order_id: type: string
tracking_number: type: string carrier:
type: string shipped_at: type: string
format: date-time
Appendix J: Quiz Answers & Solutions
Chapter 1 Answers
Q1. API stands for Application Programming Interface. Its primary purpose is to enable different
software applications to communicate with each other through a defined set of rules and protocols.
Q2. (1) Restaurant waiter — takes your order (request) to the kitchen (server) and brings back food
(response). (2) Electrical outlet — provides a standard interface for accessing electricity without needing
to understand the power grid. (3) Universal remote — sends standard commands to different devices
using a defined protocol.
Q3. Public APIs are available to any developer (e.g., Google Maps). Private APIs are used only within an
organization. Partner APIs are shared with specific business partners under formal agreements.
Q4. 2000.
Q5. Method (verb), URL (endpoint), Headers, Body (optional).
Q6. curl and httpie.
Q7. 200 OK.
Q14. JSON. It's lighter than XML, human-readable, natively supported by JavaScript, and has simpler
parsing in all languages.
Q15. curl -H "Accept: application/json" [Link]
Chapter 2 Answers
Q1. HTTP/2 introduces multiplexing (multiple streams over one connection), header compression
(HPACK), server push, and binary framing. HTTP/1.1 uses text-based protocol with head-of-line blocking.
Q3. 401 means "not authenticated" (credentials missing or invalid). 403 means "authenticated but not
authorized" (you are who you say, but you don't have permission).
Q5. 201 Created, with a Location header pointing to the newly created resource.
Chapter 3 Answers
Q1. Client-Server, Stateless, Cacheable, Uniform Interface, Layered System, Code on Demand (optional).
Q2. The Richardson Maturity Model measures REST compliance across 4 levels (0–3). Most real-world
APIs are at Level 2 (resources + HTTP verbs).
Q5. gRPC uses Protocol Buffers, a binary serialization format. Binary encoding is more compact than
JSON text, and proto schemas enable faster parsing through code generation rather than runtime
reflection.
Chapter 4 Answers
Q1. API-First means designing the API specification before writing code. Advantages: (1) parallel
frontend/backend development, (2) better design through early review, (3) automatic documentation
generation from the spec.
Q3. Cursor-based pagination scales better. Offset-based requires the database to scan and skip rows
(O(n)), becoming slow on large datasets. Cursor-based uses indexed lookups (O(log n)).
For complete solutions to all exercises including full source code, refer to the companion code repository
referenced in the Back Matter section.
References
Books
● Fielding, R.T. (2000). Architectural Styles and the Design of Network-based Software
Architectures. Doctoral dissertation, UC Irvine.
● Richardson, L. & Ruby, S. (2013). RESTful Web APIs. O'Reilly Media.
● Lauret, A. (2019). The Design of Web APIs. Manning Publications.
● Siriwardena, P. (2020). Advanced API Security: OAuth 2.0 and Beyond. Apress.
● Newman, S. (2021). Building Microservices, 2nd Edition. O'Reilly Media.
● Kleppmann, M. (2017). Designing Data-Intensive Applications. O'Reilly Media.
● Burns, B. (2018). Designing Distributed Systems. O'Reilly Media.
● Geewax, J. (2021). API Design Patterns. Manning Publications.
RFCs & Specifications
● RFC 7231 — HTTP/1.1 Semantics and Content
● RFC 7807 — Problem Details for HTTP APIs
● RFC 8594 — The Sunset HTTP Header Field
● RFC 6749 — The OAuth 2.0 Authorization Framework
● RFC 7519 — JSON Web Token (JWT)
● RFC 6902 — JavaScript Object Notation (JSON) Patch
● RFC 7396 — JSON Merge Patch
● RFC 9110 — HTTP Semantics (supersedes 7231)
● OpenAPI Specification 3.1.0 — [Link]
● GraphQL Specification — [Link]
● AsyncAPI Specification — [Link]
● Protocol Buffers Language Guide — [Link]
Online Resources
● OWASP API Security Top 10 — [Link]/API-Security
● Google API Design Guide — [Link]/apis/design
● Microsoft REST API Guidelines — [Link]/microsoft/api-guidelines
● Stripe API Reference — [Link]/docs/api (gold standard for API documentation)
● Postman Learning Center — [Link]
● ByteByteGo System Design — [Link]
● gRPC Documentation — [Link]/docs
● Kubernetes API Conventions — [Link]/docs
Acknowledgements
This guide was created to help Sasank and fellow developers master the art and science of API
development. Special thanks to the open-source communities behind OpenAPI, GraphQL, gRPC, and the
countless developers who contribute to the tools, frameworks, and standards that make modern API
development possible.
The API ecosystem thrives because of a culture of sharing knowledge, writing documentation, and
building tools that make other developers' lives easier. This guide is a contribution to that tradition.
Index
Term Chapter(s)
API-First Design 1, 4
API Gateway 14
API Key 8
AsyncAPI 3, 18, App I
Authentication 8
Authorization 8, 13
Term Chapter(s)
BOLA 13
Cache-Control 2, 16
Caching 5, 16
Circuit Breaker 14, 17
CORS 2
curl 1, App C
Cursor Pagination 4, 5
DataLoader 6
Docker 1, 17, App C
Error Handling 4
ETag 2, 5, 16
Event Sourcing 18
FastAPI 5, 17
GraphQL 3, 6, 17
gRPC 3, 7, 17
HATEOAS 3, 4
Health Check 15
HTTP Methods 2
HTTP Status Codes 2
HTTP/2 2, 7
HTTP/3 2
Idempotency 4
JWT 8
k6 12
Kong 14
Kubernetes 17, App C
Load Testing 12
Logging 15
Term Chapter(s)
Microservices 14, 17, 18
Monitoring 15
mTLS 8, 14
N+1 Problem 6
OAuth 2.0 8
Observability 15
OpenAPI 4, 11, App D
OpenTelemetry 15
OWASP API Top 10 13
Pagination 4, 5
Performance 16
PKCE 8
Postman 1
Protocol Buffers 7, App E
Rate Limiting 9
RBAC 8
Redis 9, 16
REST 3, 5
RFC 7807 4
Richardson Maturity Model 3, 5
Saga Pattern 18
Security 8, 13, App F
Serverless 18
Service Mesh 14
SLA/SLO/SLI 15
SOAP 3
Spring Boot 5, 17
SSE 2
Term Chapter(s)
Stripe 1, 19, 20
System Design 20
Testing 12, App G
TLS/HTTPS 2
Token Bucket 9
Tracing 15
Versioning 10
Webhooks 3, 5
WebSocket 2, 3
API Study Guide — Beginner to Expert
Prepared for Sasank | Version 1.0 | April 2026
© 2026 — All rights reserved.