Section 4: Two Doors, One Contract - API Design (with Pushback)
Executive Summary: This section writes the shortener's public contract: one unauthenticated redirect on the short domain, and four authenticated endpoints to create, inspect, disable and list links. Each choice is defended in a live exchange: why POST and not PUT, why never a GET /shorten, why the same long URL gets a fresh code, why 302 and not 301, why a non-idempotent create still carries an Idempotency-Key, and why the short domain serves nothing but redirects. The contract is small on purpose. Section 3's arithmetic says one door takes about 116 K requests a second and the other about 1.2 K, so the two doors should not look alike.
The interviewer caps the marker and leans back: "Okay, you have your numbers. Show me the API." You don't start with a list of endpoints. You start with the asymmetry from Section 1, because that asymmetry decides the shape of the contract:
GET tiny.example/{short_code} redirect (anonymous, ~116 K/s avg)
POST /v1/links create (authenticated, ~1.2 K/s avg)
GET /v1/links/{short_code} metadata (owner only)
DELETE /v1/links/{short_code} disable (owner only)
GET /v1/links?cursor=...&limit=50 list my links
"The first line is the product," you say. "The other four are a management console. They have different callers, different authentication, different SLOs, and they live on different domains."
The Create Call
Maya's newsletter tool calls this endpoint once per campaign:
POST /v1/links
Authorization: Bearer <api-key>
Idempotency-Key: 6f1c2e0a-8b4d-4c1e-9a7f-3d2b5e8c1a90
Content-Type: application/json
{ "long_url": "https://shop.example.com/collections/fall-2026/running-shoes?utm_source=newsletter&utm_medium=email&utm_campaign=oct-launch",
"expires_at": null }
201 Created
Location: /v1/links/aZ3kP9q
{ "short_code": "aZ3kP9q",
"short_url": "https://tiny.example/aZ3kP9q",
"long_url": "https://shop.example.com/collections/fall-2026/...",
"created_at": "2026-10-01T09:00:00Z",
"expires_at": null }
Notice what the client does not send: a code, an owner ID, or a redirect type. The owner comes from the verified credential, so no request can create a link on someone else's account. The code is chosen by the server (Section 8 covers how). expires_at is optional, and null means the link does not expire (Section 3 sizes storage over a 5-year horizon). Location names the created API resource; the shareable link is short_url in the body.
Failures are deliberately specific. 400 means the URL is malformed or longer than 2,048 characters. 422 means it parsed fine but the scheme isn't http or https, so javascript: and data: URLs are turned away; 422 is also returned when the destination is on a threat list (Section 10 adds the rest of the abuse checks). 429 with Retry-After means a per-key rate limit tripped. All of this has to fit inside the p99 < 200 ms create budget from Section 2.
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson