Tech Literacy for PMs
3 / 9
Lesson 3 of 9

Session 03: APIs in Depth — REST, Auth, and Rate Limiting

20 min readViet-Anh NguyenViet-Anh Nguyen
Session goals

Session goals

When the backend says "the API isn't ready, so frontend can't build it yet," you know how to unblock — instead of just waiting.

You'll walk away knowing:

  • The anatomy of an API request: URL, method, headers, body, response
  • GET/POST/PUT/PATCH/DELETE — when to use each and why it matters
  • Authentication: API key, OAuth, JWT — what a PM needs to understand about each
  • What rate limiting is and how it shapes feature design
  • API versioning — why /v1/ and /v2/ live side by side
  • Reading Swagger/OpenAPI docs and calling an API yourself with Postman

Duration: 90–120 minutes, including 30 minutes of hands-on Postman practice

1/8

Part 1: Anatomy of an API — Read a request like you read text

Session 01 introduced the API as "a contract between two systems" — send the right request, get the right data back. Today we look at what that contract actually specifies: URL, method, auth, rate limit, and versioning.

A URL isn't just an address

Think of an API like a restaurant: the URL is the address and table number, the method is the kind of request (order food, pay, cancel a dish), the headers are service details (who's the VIP guest, preferred language), and the body is the specific request content (which dish, how many).

An API's URL carries more information than a regular web page's URL. Look at:

https://api.shopee.vn/v2/shops/1234/products?category=electronics&limit=20&page=2

Break it down piece by piece:

  • https://api.shopee.vn — base URL: the API server's domain, like the restaurant's address
  • /v2/ — version: this is API version 2
  • /shops/1234/ — resource hierarchy: the shop with ID 1234, like "the area belonging to store 1234"
  • /products — resource type: fetch that shop's product list
  • ?category=electronics — query parameter: filter the category to "electronics"
  • &limit=20&page=2 — pagination: get 20 products, page 2

When a PM can read this URL, they can immediately tell: the "filter by category" feature already exists in the API (just add a query parameter), and the "get a seller's products" feature already has an endpoint (no new build needed). This is a skill that saves time for the whole team.

Loading diagram…

Methods aren't picked arbitrarily

A common design mistake from the PM side: writing a feature spec without stating the method, leaving the dev to decide. The typical fallout:

  • POST /orders to create an order — correct
  • GET /orders/cancel?id=123 to cancel an order — wrong. GET should have no side effects. If a browser or an automated bot hits this URL, the order gets cancelled with nobody realizing it
  • DELETE /orders/123 to cancel an order — better if cancellation is permanent and irreversible
  • PATCH /orders/123 with body {"status": "cancelled"} — best if "cancel" is a status change, because you can later add new statuses without a new endpoint

This distinction affects how the frontend handles errors, how caching behaves, and how the API gateway writes audit logs.

Loading diagram…

Part 2: Authentication — Three mechanisms and when each fits

API Key — The simplest, and the least safe when used in the wrong place

An API key is a secret string, attached to every request as an identity badge. Picture it like a hotel room key — whoever holds it gets in, no matter who they are.

It's typically used for server-to-server communication — for example, your backend calling Twilio's API to send an SMS, or your backend calling OpenAI to process text.

Authorization: ApiKey sk_live_a8f3c9d2e1b7...

The problem: API keys have no expiry by default. If one leaks, the attacker has full access until you revoke it. Never use an API key on the frontend — JavaScript running in the browser can be read by anyone who opens DevTools.

What a PM needs to know: When integrating a third-party API (payment, email, SMS), ask right away: "Where is this API key stored, and what's the process for rotating it?" That question catches security holes earlier than a security audit would.

OAuth — Authorization without sharing a password

OAuth is an authorization protocol. When a user clicks "Sign in with Google," they don't share their Google password with your app — Google authenticates them and returns a token with limited access.

Think of it like this: you hand your ID card to a hotel so they can photocopy it to verify your identity, but you don't hand over your whole wallet and house keys. OAuth does the same — your app only receives the information the user agreed to share.

The full flow:

Loading diagram…

What a PM needs to know: OAuth is not simple to implement yourself. If a sprint estimate has "Social login," ask: "Are we implementing OAuth ourselves or using a service like Auth0 or Firebase Auth?" Doing it right yourself takes 2–3 sprints. Using an off-the-shelf service takes 2–3 days.

JWT — The self-verifying token

JWT (JSON Web Token) is a token that carries user info signed with a secret key. Picture an employee badge with a photo and details — anyone looking at it knows who this person is and what they're allowed to do, without calling HR to confirm.

The server doesn't need to query the database on every authentication — it just checks the signature on the token.

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEyMywicm9sZSI6InVzZXIiLCJleHAiOjE3MTE3MDAwMDB9.abc123

The token looks like a jumble of random characters, but it's actually three parts separated by dots. The middle part (payload), once decoded, is:

{ "userId": 123, "role": "user", "exp": 1711700000 }

A PM needs to know two things about JWT:

First: JWTs have an expiry. When a token expires, the user is logged out and has to sign in again. A short expiry (say, 15 minutes) is safer but more annoying. A long expiry (7 days) is more convenient but riskier if the token is stolen. This is a product decision, not just a technical one.

Second: a JWT can't be revoked before it expires — unless you keep a blacklist, and that needs extra infrastructure. When a PM asks for "log out of all devices immediately" (say, when a user reports a lost phone), ask the dev right away: "Do we have a JWT blacklist?"

API KeyOAuthJWT
MechanismSecret string, sent with every requestUser delegates via a third party, no password sharedSelf-verifying token: carries user info + a digital signature
Use whenServer-to-server (backend calls backend)"Login with Google/Facebook"The session after login
UpsideSimple, easy to deploySafe for the user, no password exposedFast — no DB query per request
RiskOften never expires, hard to revokeMore complex, depends on a third partyCan't be revoked before expiry (unless you have a blacklist)
PM should ask"How often is this key rotated?""If Google is down, can users still log in?""How long is the token expiry? Is there a blacklist?"

Part 3: Rate Limiting, Versioning, and Error Handling

Rate Limiting — Designing features within the limits

Rate limiting protects an API from overload — like a store serving at most 100 customers at once. But it also directly shapes feature design in ways PMs often don't anticipate.

A real example — the realtime search feature:

The PM asks: "When the user types in the search box, show suggestions instantly with each keystroke."

The problem: the user types 10 characters fast in 2 seconds → 10 API requests. With 10,000 users typing at once: 100,000 requests in 2 seconds. If the search endpoint's rate limit is 60 requests/minute per user, a fast typer gets blocked within a few seconds.

Loading diagram…

The technical solution is debouncing — wait until the user stops typing for 300ms before sending the request. The PM needs to know this to write correct acceptance criteria: "Suggestions appear after the user stops typing for 300ms, not on every keystroke."

Questions to ask before designing any feature that uses an API:

  • What's the rate limit on this endpoint (requests per unit of time)?
  • Is the limit per user, per IP, or per API key?
  • When rate-limited, how does the UX handle it? What message shows?

API Versioning — Managing change without breaking clients

Imagine you provide a form for partners to fill out. One day you want to split the "Full name" field into two separate fields, "Last name" and "First name." If a partner is using the old form, they'll break instantly. API versioning solves this — keep the old form working while launching a new one for whoever wants it.

When you need to change an API in a backward-incompatible way, there are three common approaches:

  1. URL versioning: /v1/users, /v2/users — the most common, easy to read and debug
  2. Header versioning: API-Version: 2024-01-01 — cleaner URLs but harder to debug when something goes wrong
  3. Query parameter: /users?version=2 — less common, easy to accidentally omit

Breaking changes PMs often create unintentionally when writing specs:

  • "Rename field user_name to full_name" — the old mobile app gets null instead of the user's name and shows blank or crashes
  • "Remove field legacy_id from the response" — a partner using that field to sync systems breaks immediately
  • "Change the date format from 2026-03-29 to 29/03/2026" — the frontend parsing dates in the old format fails and shows "Invalid Date"

Before speccing any change to a data structure, ask: "Is anyone consuming this field? Does this change break existing clients?" The question costs 30 seconds; the answer can save a whole sprint.


Part 4: Hands-on — Postman and API Documentation

Reading Swagger as a PM

Swagger (also known as OpenAPI) is the standard for writing API documentation. It's like a restaurant menu — it lists all the "dishes" (endpoints), the ingredients they take (parameters), and describes what comes back (responses).

Swagger UI is usually hosted at /api/docs or /swagger in your project. Look at a typical endpoint:

GET /orders/{orderId}

Parameters:
  orderId (path, required): integer — the order ID to view

Responses:
  200: Order object
    {
      "id": 456,
      "status": "completed",
      "total_price": 450000,
      "items": [...],
      "created_at": "2026-03-01T10:30:00Z"
    }
  401: Unauthorized — not logged in
  403: Forbidden — not this user's order
  404: Order not found

From this, a PM immediately draws out:

  • The items field is already in the response — no need for a separate endpoint to fetch the products in an order, saving a whole sprint
  • Need to handle 403 in the UX — when a user tries to access someone else's order, what message shows?
  • created_at is ISO 8601 format (e.g., 2026-03-01T10:30:00Z) — the frontend needs to reformat it into "01/03/2026 10:30" for the user. If the spec doesn't say so, a dev might display the raw format
Loading diagram…

Postman: Three core skills

Postman is a tool that lets you call APIs directly, view what comes back, and test auth — all through a visual interface without writing a single line of code. This is the most important hands-on skill in this session.

1. Create and send a request:

Open Postman → New Request → choose a method (GET, POST...) → enter the URL → hit Send. The response shows right below with the status code, response time, and the full body. This is the fastest way to confirm an API is working correctly before you write a spec that depends on it.

2. Use Environment Variables:

Instead of hardcoding https://api.production.com into every request, create a "Development" environment with the variable baseUrl = http://localhost:3000 and a "Production" environment with baseUrl = https://api.production.com. Switch between environments with one click — no need to edit each request when you want to test against production.

3. Test Auth:

Create a POST /auth/login request with a username and password → grab the token from the response → copy it into the Authorization header of your other requests. Postman can do this automatically with Scripts — the token gets passed along after each login. A PM uses this skill to verify a feature themselves before handing it to QA.


Further reading


Homework

Try calling a real API with Postman — no coding needed.

Postman is a tool for "talking" directly to an API, like texting a system and seeing what it replies.

  1. Open web.postman.co in your browser (free, no install needed).
  2. Create a new request: choose GET, enter the URL https://jsonplaceholder.typicode.com/users/1, hit Send.
  3. Look at what comes back: this is the info for a fake user. What do you see? Are there any fields you didn't expect?
  4. Try changing the 1 to 2, 3 — each number is a different user. This is exactly how your app fetches user data from the backend.
  5. Share to the group: Screenshot the result and answer: If the "view user profile" feature needs to show a name and email, does this API already have enough data?

What matters

  1. 1An API's URL carries enough information to read the resource hierarchy, version, and query parameters. Read the URL before asking the dev what that endpoint does.
  2. 2HTTP methods aren't arbitrary: GET reads, POST creates, PUT replaces, PATCH partially updates, DELETE deletes. The wrong method leads to a bug that comes from the spec.
  3. 3Authentication comes in three common forms: API key (server-to-server), OAuth (social login), JWT (web/mobile app). Each has its own tradeoff between security and UX.
  4. 4Rate limiting directly shapes feature design. Ask for the rate limit on every endpoint before speccing a realtime or bulk-operation feature.
  5. 5A breaking change is an API change that breaks existing clients. Renaming a field, removing a field, changing a format — they're all breaking changes.