Web APIs
Course Review
Walk back through all 38 lessons, map every concept to the production system that is now live, and consolidate everything into a reference you will actually use on your next API project.
Most courses end with a project and call it done. But the most valuable thing that happens after you build something is the review — the moment you look back at what you made and understand why each piece exists, how the pieces connect, and what you would do differently next time. That understanding is what transfers to the next project.
The APIForge Platform API v1 is live. It handles authentication, serves resources over a versioned REST API, paginates with cursors, searches with a dedicated index, uploads files via pre-signed URLs, fires signed webhooks, enforces rate limits, and runs under HTTPS with process management and health monitoring. Every one of those features maps back to a specific lesson in this course.
This lesson does three things: maps the complete course content to the production system, identifies the patterns that appear across multiple lessons, and builds a decision reference — the questions to ask and the patterns to reach for when you start your next API project from scratch.
The Full Course Map — 38 Lessons to One Production System
Every lesson in this course was building toward the same target. The concepts in Lesson 5 (HTTP basics) are the foundation that makes Lesson 34 (API case study) comprehensible. The auth middleware in Lesson 32 is the same code used in Lesson 37 (final project). The rate limiter explained in Lesson 23 is the same one deployed in Lesson 38. Nothing was taught in isolation.
| Lessons | Topic Group | Where It Appears in Production |
|---|---|---|
| 1–8 | API Fundamentals — what an API is, HTTP, methods, status codes, request and response | Every single endpoint. 201 on create, 404 on missing resource, 401 on bad auth, 429 on rate limit — all from Lesson 7. |
| 9–16 | REST Architecture — principles, resource modeling, CRUD, pagination, versioning, error handling | The /api/v1/* prefix, PATCH for partial updates, cursor pagination on every list endpoint, the structured error object with type, code, param, request_id. |
| 17–24 | Security — authentication, authorization, API keys, OAuth, JWT, CORS, rate limiting, security best practices | JWT auth middleware, refresh token flow, Redis rate limiter with X-RateLimit headers, HMAC webhook signatures, CORS headers in Nginx. |
| 25–30 | Tooling — API documentation, OpenAPI, testing, Postman, monitoring, performance | Gzip compression, N+1 query elimination, Redis caching, async background jobs, the 40 acceptance criteria from Lesson 36 as the test plan. |
| 31–35 | Projects — REST API build, Auth API, Gateway, Case Study, Real-World Use Cases | The complete auth layer from L32, gateway patterns from L33, Stripe patterns (idempotency, cursor pagination, signed webhooks) from L34, payment and file upload flows from L35. |
| 36–38 | Delivery — Project Planning, Final Project, Deployment | The live production system: 19 endpoints, four phases, PM2 cluster, Nginx HTTPS, health monitor, Let's Encrypt certificate. |
The Patterns That Appear Everywhere
Across 38 lessons, certain patterns appeared repeatedly — in different lessons, applied to different problems, but recognisably the same underlying idea. These are the patterns worth internalising. When you encounter a new API problem, your first question should be: which of these does this resemble?
The Decision Framework — Questions to Ask on Every New API
Every time you start a new API project or integrate with a new third-party service, the same set of questions applies. These are not questions you answer once and forget — they are a checklist you revisit at each stage of the build. The APIForge team runs through this list at every sprint planning session.
# WHAT: API project decision checklist — ask these before and during every build
# ── DESIGN ─────────────────────────────────────────────────────────────────
[ ] What is the resource model? Name every noun the API exposes.
[ ] What HTTP method maps to each operation?
GET to read, POST to create, PATCH to partial update, PUT to replace, DELETE to remove.
[ ] What status code does each operation return on success and on each error?
[ ] Are list endpoints paginated? Cursor for live data, offset for static snapshots.
[ ] Are update endpoints PATCH (partial) or PUT (full replacement)?
[ ] What fields belong in the response? Remove anything the client does not need.
# ── SECURITY ───────────────────────────────────────────────────────────────
[ ] Which endpoints require authentication?
[ ] What authentication mechanism? JWT for stateless, sessions for stateful.
[ ] What is the token lifetime? Short-lived access + long-lived refresh is the standard.
[ ] What authorization is needed? Who can do what — role check or ownership check?
[ ] Is rate limiting needed? Per user, per IP, or per API key?
[ ] Are there inbound webhooks? Verify HMAC signatures before processing.
[ ] Are there third-party integrations? OAuth 2.0 — never ask for passwords.
[ ] Where are secrets stored? Environment variables. Never in source control.
# ── RELIABILITY ────────────────────────────────────────────────────────────
[ ] What happens if a downstream service (Slack, S3, Stripe) is slow or down?
Move to a background queue. Do not block the request path.
[ ] Can clients safely retry failed requests?
Add idempotency keys to any endpoint where duplicate execution causes harm.
[ ] What gets cached? Hot reads that change less often than they are requested.
[ ] What is the database query pattern for each list endpoint?
Check for N+1 queries. Use JOINs or batch loads.
[ ] Are there missing database indexes?
Every WHERE clause column and every foreign key needs an index.
# ── ERRORS ─────────────────────────────────────────────────────────────────
[ ] Is there a shared error builder used by every controller?
[ ] Does every error response include: type, message, code, param, request_id?
[ ] Does the global error handler strip stack traces from production responses?
[ ] Are specific HTTP status codes used for specific errors?
400 bad input, 401 auth, 403 forbidden, 404 not found, 409 conflict, 429 rate limit.
# ── DEPLOYMENT ─────────────────────────────────────────────────────────────
[ ] Is NODE_ENV=production set on the server?
[ ] Are environment variables in a 600-permission file, not in source control?
[ ] Is the process managed by PM2 with pm2 save and pm2 startup configured?
[ ] Is there a reverse proxy (Nginx) handling HTTPS and X-Forwarded-For?
[ ] Is there a health check endpoint and a monitor that alerts on failure?
[ ] Is there a recovery alert — not just a down alert?Running the completed API through the decision checklist confirmed all 30 items passing. But the value of the checklist is not in the final audit — it is in running it at the start of a project, before any code exists. Items that are not checked before building tend to be retrofitted under time pressure, which produces inconsistent implementations and missed edge cases.
Notice that the checklist does not mention any specific technology. It does not say "use Redis" or "use PM2" or "use PostgreSQL." It asks questions — and the answers drive the technology choices. A different project might answer "is there a reverse proxy?" with Caddy instead of Nginx, or answer "what is the caching layer?" with Memcached instead of Redis. The questions stay constant. The answers change per project.
Try this: Take your most recent personal or work project and run it through this checklist right now. The items that come back unchecked are your technical debt inventory — not things to fix immediately, but things to be aware of and prioritise in the next sprint.What to Study Next
Finishing this course puts you at a specific point on the API development map. You can design, build, secure, test, and deploy a production REST API. The next layer of depth branches in three directions depending on what your work actually requires.
Quick Reference — Every Key Concept
This reference maps every major concept from the course to its lesson, its one-line definition, and where it appears in the APIForge production system. Bookmark this page — it is the reference you reach for when you remember the concept but not the details.
# WHAT: Complete concept reference — APIForge Web APIs course
# ── HTTP FUNDAMENTALS ──────────────────────────────────────────────────────
HTTP Methods (L6)
GET — read a resource, no side effects, safe to retry
POST — create a resource or trigger an action
PUT — replace a resource entirely
PATCH — update specific fields of a resource
DELETE — remove a resource
Status Codes (L7) — most important ones
200 OK — read, update, delete success
201 Created — resource successfully created
202 Accepted — request received, processing async
301 Moved — permanent redirect
400 Bad Request — client sent invalid input
401 Unauthorized — authentication required or failed
403 Forbidden — authenticated but not permitted
404 Not Found — resource does not exist
409 Conflict — duplicate or state conflict
413 Too Large — payload exceeds size limit
415 Unsupported — media type not accepted
429 Too Many — rate limit exceeded
500 Server Error — unhandled server-side failure
502 Bad Gateway — upstream service unreachable
503 Unavailable — server temporarily unable to handle request
# ── REST DESIGN ────────────────────────────────────────────────────────────
REST Principles (L10)
Stateless — each request carries all context, no server-side session
Resource-based — URLs name things (nouns), methods name actions (verbs)
Uniform interface — consistent structure across all endpoints
Cursor Pagination (L14, L34)
Use when: data is live and changes between page requests
How: WHERE id < cursor ORDER BY id DESC LIMIT n+1
Signal: has_more: true/false tells client when to stop
Versioning (L15, L34)
URL prefix: /api/v1/* — simple, visible, forces migration
Header-based: APIForge-Version: 2024-11-01 — client controls migration timing
# ── AUTHENTICATION AND SECURITY ────────────────────────────────────────────
JWT (L21, L32)
Header.Payload.Signature — base64 encoded, not encrypted
Verify with: jwt.verify(token, secret) — throws on invalid or expired
Access token: short-lived (2h), carries userId, email, role
Refresh token: long-lived (7d), carries userId and type:"refresh" only
bcrypt (L32)
Salt rounds 10 — each hash takes ~100ms, brute force impractical
Compare: bcrypt.compare(plain, hash) — never compare plain text
Rate Limiting (L23, L30)
Redis atomic incr — race-condition-safe counter
Key format: rl:{userId}:{windowMinute}
Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
429 response must include Retry-After header
HMAC Webhook Signatures (L34, L35)
Sign: HMAC-SHA256(secret, timestamp + "." + body)
Header: APIForge-Signature: t={ts},v1={sig}
Verify: recompute and compare — reject if timestamp older than 5 min
OAuth 2.0 (L20, L35)
state parameter — CSRF protection on the callback
Scopes — minimum required permissions only
Token storage — encrypted at rest, never logged
# ── PERFORMANCE ────────────────────────────────────────────────────────────
N+1 Queries (L30)
Problem: 1 query for list + N queries for each row's related data
Fix: JOIN query or batch load with IN clause
Compression (L30, L38)
gzip level 6 — best ratio/speed balance for JSON payloads
JSON compresses 85-95% — 1.4MB becomes 89KB
Idempotency Keys (L34, L37)
Client generates per logical operation (not per retry)
Server stores response in Redis with 24h TTL
Replay: return stored response, add Idempotency-Replayed: true header
Pre-signed URLs (L35)
Client requests URL from API (tiny request)
Client uploads directly to S3 using URL (no API server involved)
URL expires in 5 minutes — capability token, not permanent access
# ── DEPLOYMENT ─────────────────────────────────────────────────────────────
PM2 (L38)
cluster mode — one process per CPU core
pm2 save — persist process list across reboots
pm2 startup — register PM2 as systemd service
pm2 reload — zero-downtime reload (new code, same port)
Nginx (L38)
Reverse proxy — forwards HTTPS to Node on localhost:3000
X-Forwarded-For — passes real client IP to Node
HSTS — forces HTTPS at browser level for 1 year
Environment Security (L38)
chmod 600 .env — owner read/write only
Never commit .env — only .env.example goes to git
Boot validation — crash with clear error if required var missingThe reference confirms what the course map showed: the most important concepts are the ones that appeared in multiple lessons. JWT verification, Redis, error handling, middleware, and background queues each appeared in 4 or 5 different lessons — not because the curriculum was repetitive, but because those patterns genuinely apply to that many different problems. Repetition across contexts is the signal that something is worth memorising.
The five patterns that appeared in both theory lessons and the final project build are the ones to prioritise. You did not just read about cursor pagination — you read the concept (L14), analysed a real API that uses it (L34), and built it from scratch in SQL (L37). That three-stage exposure is what makes a concept stick.
Try this: Pick any concept from the reference above that feels least solid. Find the lesson number listed next to it, go back to that lesson, and re-read just the "What just happened?" box. That single paragraph contains the most important insight from the lesson. Ten minutes of targeted review beats re-reading the whole lesson.Before and After: Start of Course vs End of Course
The shift from Lesson 1 to Lesson 39 is not just knowledge accumulation. It is a change in how you think about API problems — from reacting to error messages to anticipating failure modes, from copying endpoint patterns to designing resource models, from shipping features to shipping systems.
Quiz
1. The APIForge course applied the same core pattern to Slack notifications, webhook delivery, and PDF exports — all in different lessons. What is the name of this pattern and what problem does it solve?
2. The decision checklist recommends cursor pagination for live data and offset pagination for static snapshots. What is the specific failure mode of offset pagination that cursor pagination avoids?
3. The APIForge decision checklist includes the question: does the global error handler strip stack traces from production responses? Why does this matter from a security perspective?