Week 7 — API Design & Blob Storage
API Paradigms
Section titled “API Paradigms”| REST | GraphQL | gRPC | |
|---|---|---|---|
| Protocol | HTTP/1.1 | HTTP/1.1 | HTTP/2 |
| Format | JSON | JSON | Protobuf (binary) |
| Fetching | Fixed endpoints → fixed response | Client specifies exact fields | Strongly typed contracts |
| Caching | Easy (HTTP cache headers) | Hard (POST requests) | Hard |
| Browser support | Yes | Yes | No (needs proxy) |
| Best for | Public APIs, external | Mobile, flexible frontends | Internal microservices |
REST Design Principles
Section titled “REST Design Principles”Resource naming
Section titled “Resource naming”# Good — nouns, pluralGET /api/v2/invoicesPOST /api/v2/invoicesGET /api/v2/invoices/123PATCH /api/v2/invoices/123DELETE /api/v2/invoices/123
# Bad — verbsPOST /api/getInvoicePOST /api/createInvoiceVersioning
Section titled “Versioning”/api/v1/invoices ← old clients still work/api/v2/invoices ← new clients use thisNever break existing clients by changing v1. Add v2 for breaking changes.
Idempotency Keys
Section titled “Idempotency Keys”Critical for financial operations — prevent duplicate processing when client retries:
POST /api/v2/paymentsIdempotency-Key: 550e8400-e29b-41d4-a716-446655440000
{ "amount": 5000, "currency": "AUD" }Server stores the key + result. Same key → return cached result, don’t process again.
Pagination
Section titled “Pagination”Offset Pagination (simple, avoid at scale)
Section titled “Offset Pagination (simple, avoid at scale)”SELECT * FROM orders ORDER BY id LIMIT 20 OFFSET 10000;-- PostgreSQL must scan and skip 10,000 rows — gets slower as offset growsKeyset / Cursor Pagination (recommended)
Section titled “Keyset / Cursor Pagination (recommended)”-- First pageSELECT * FROM orders WHERE id > 0 ORDER BY id LIMIT 20;-- Returns last id = 5234
-- Next pageSELECT * FROM orders WHERE id > 5234 ORDER BY id LIMIT 20;-- Instant — uses the indexReturn a cursor in the response:
{ "data": [...], "next_cursor": "eyJpZCI6NTIzNH0=", "has_more": true}File / Blob Storage
Section titled “File / Blob Storage”Never Store Large Files in PostgreSQL
Section titled “Never Store Large Files in PostgreSQL”Problems:
- Bloats WAL logs — slows replication
- Bloats backups — uncompressible binary data
- Fills RAM (PostgreSQL buffer pool evicts useful data)
- Slow streaming through the app server
Object Storage (S3 Pattern)
Section titled “Object Storage (S3 Pattern)”Client → App server (get pre-signed URL) → Client uploads directly to S3Client → App server (get pre-signed URL) → Client downloads directly from S3App server never touches the file bytes. S3 handles:
- Durability (11 nines — effectively never loses data)
- Global replication
- CDN integration
- Lifecycle policies (archive old files automatically)
Pre-signed URL: a temporary URL that allows a specific operation (upload or download) without requiring credentials. Expires after N minutes.
Practice
Section titled “Practice”Design the file attachment system for an ERP:
- Users upload invoices (PDF), contracts, product images
- 500k files/day, average 2MB each = 1TB/day
- Files must be accessible for 7 years (compliance)
- Some files are confidential (access control required)
Self-check
Section titled “Self-check”- Why does GraphQL break HTTP caching?
- What happens if a client retries a payment without an idempotency key?
- At what scale does offset pagination become a real performance problem?