BiTree
  • Search For Lessons
  • Curriculum
  • Pricing
  • For Educators
  • Become a Tutor
  • About
  • Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
BiTree

Live coding lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Search For Lessons
  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Become a Tutor
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 BiTree. All rights reserved.
Curriculum/Web Development/Working With APIs: HTTP, Status Codes, Postman, and fetch
45 minBeginner

Working With APIs: HTTP, Status Codes, Postman, and fetch

After this lesson, you will be able to: Read API documentation confidently, test endpoints in Postman or Bruno, recognize and interpret every common HTTP status code, call APIs from JavaScript with fetch + async/await + try/catch, and handle authentication via headers.

Every modern app talks to APIs. A frontend that loads users, a backend that integrates Stripe, an AI tool that calls Anthropic's API — they all speak HTTP. This lesson takes you from zero understanding of APIs to comfortable reading docs, testing endpoints, handling errors, and shipping a real network call in your own app. Working with APIs is a core professional skill: in every junior developer interview it's the line that separates candidates who built something real from candidates who only finished tutorials.

Prerequisites:JavaScript and the DOM

What an API actually is

API stands for Application Programming Interface. In practice, when people say "API" today they almost always mean a REST API: a server that exposes a set of URLs (called endpoints) you can hit with HTTP requests to read or change data, usually exchanged as JSON. Think of an API as a menu: the documentation lists what's available, what each item costs (what input it needs), and what you get back. Your code is the customer placing the order.

HTTP methods, the four you use daily

REST APIs use HTTP verbs to describe intent. **GET** reads data (`GET /users/1` → user 1's profile). Should be safe and have no side effects. **POST** creates new data (`POST /users` with a JSON body → creates a user). **PUT** replaces data (`PUT /users/1` with the full new user object). **DELETE** removes data (`DELETE /users/1`). There's also `PATCH` (partial update) and `OPTIONS` (used by browsers for CORS preflight), but the four above cover 95% of what you'll write.

HTTP status codes, what each one means

Every HTTP response has a status code. The first digit tells you the category. Memorize the bolded ones — they're the ones you'll see (and need to handle) every week.

tsx
// 2xx Success
200 OK // generic success (most GETs)
201 Created // POST that created a resource
204 No Content // success, no body (DELETEs, some PUTs)
// 3xx Redirect (usually handled transparently by the browser)
301 Moved Permanently
302 Found // temporary redirect
304 Not Modified // cache hit
// 4xx Client error — YOUR request was wrong
400 Bad Request // malformed payload, missing field, invalid type
401 Unauthorized // no/invalid auth credentials
403 Forbidden // authenticated, but not allowed
404 Not Found // the resource doesn't exist
409 Conflict // e.g. signing up with an email that's taken
422 Unprocessable // validation failed (common in REST APIs)
429 Too Many Requests// you hit the rate limit
// 5xx Server error — the SERVER broke, not you
500 Internal Server Error
502 Bad Gateway // upstream service failed
503 Service Unavailable
504 Gateway Timeout

💡 The 401 vs 403 rule

401 = the server doesn't know who you are (no token, expired token, bad credentials). The fix is on the client: send valid auth. 403 = the server knows who you are, but you don't have permission for this resource (free-tier user hitting a paid endpoint, employee hitting an admin route). The fix is on the server or in your permissions. Mixing these up in error messages is one of the most common UX bugs in junior backend code.

Reading API documentation

Good API docs follow a predictable shape. For any endpoint you'll find: the HTTP method and URL, required and optional inputs (query params for GET, JSON body for POST/PUT), the response shape (with example), authentication requirements, and rate limits. Skim in that order. Start with: what URL, what method, what auth. Then look at the example request and response — those tell you more than the prose. Two reference-quality examples to study: Stripe (stripe.com/docs/api) and GitHub (docs.github.com/rest). Both are written by teams whose business depends on developers succeeding.

Postman and Bruno — testing endpoints without writing code

Before you write fetch code, hit the endpoint in a request client. **Postman** is the dominant tool — every backend job listing assumes you've used it. **Bruno** is the open-source alternative that stores requests as files in your repo (great for team workflows). Either works; learn one, recognize both. Workflow: paste the URL, pick the method, add headers (`Authorization: Bearer ...`, `Content-Type: application/json`), add a body if POST/PUT, hit Send. The response shows status code, headers, and parsed JSON. This three-second feedback loop is what makes API development sane — if your fetch call fails, the question is always 'does it work in Postman?' If yes, your JS is wrong; if no, the API/your auth is wrong.

Calling an API from JavaScript, the full pattern

Production-quality fetch always includes: status check, JSON parse, error handling, and (often) headers for auth and content type. Memorize this template.

tsx
async function createPost(token, post) {
try {
const response = await fetch("https://api.example.com/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify(post),
});
// fetch only rejects on network failure.
// 4xx / 5xx responses still RESOLVE — you must check ok yourself.
if (!response.ok) {
const errorBody = await response.json().catch(() => ({}));
throw new Error(
`HTTP ${response.status}: ${errorBody.message ?? response.statusText}`
);
}
return await response.json();
} catch (error) {
// Network failure OR thrown HTTP error from above
console.error("createPost failed:", error);
throw error; // let the caller decide how to show this to the user
}
}
// Usage
try {
const created = await createPost(myToken, { title: "Hello", body: "World" });
console.log("Created post #", created.id);
} catch (error) {
alert("Could not save your post. Try again in a moment.");
}

Authentication: API keys, Bearer tokens, OAuth (in one sentence each)

**API key** — a long secret string the server gave you. You pass it in a header (`Authorization: Bearer YOUR_KEY` or sometimes `X-API-Key: YOUR_KEY`). Used by most third-party APIs (OpenAI, Stripe, Resend). **JWT / Bearer token** — a signed token the server issued when you logged in, sent on every request in `Authorization: Bearer ...`. Common for auth between a frontend and your own backend. **OAuth 2.0** — a flow that lets users grant your app limited access to their account on a third-party service (e.g. "Log in with Google"). The output is still a Bearer token, but the way you obtain it is more elaborate. Never put API keys in client-side code shipped to users — anyone can read it. Keep secret keys server-side and proxy the request.

⚠️ CORS — the error every JS developer hits eventually

When your browser-side JavaScript on `app.example.com` tries to fetch `api.other.com`, the browser blocks the response unless the other server explicitly opts in via CORS headers (`Access-Control-Allow-Origin`). The error in the console: *"blocked by CORS policy."* Important: CORS is enforced by the BROWSER, not the server. The same request works fine from Postman or your backend. The fixes are (1) the API owner adds your origin to their CORS allowlist, or (2) you call the API from your own backend instead and proxy the response.

Wire a real API call into a button

Build the smallest end-to-end API integration: a button that fetches a random user from https://jsonplaceholder.typicode.com/users/{1-10} and renders their name + email. The starter has the HTML scaffold and an empty handler — fill in the fetch call following the production pattern (status check, try/catch, async/await). Required patterns check for `async`, `await fetch`, `response.ok`, and `try`.

Loading exercise…
Quick Check

Your fetch returned status 401. What does that mean and what do you fix?

Pick the most accurate diagnosis.

💡 Common mistakes only experienced devs catch

Five API-integration pitfalls that bite even good juniors. (1) Forgetting `response.ok` — `fetch` only rejects on network failure; a 500 still resolves, and `.json()` on an HTML error page throws a parse error. (2) Putting API keys in client-side code — anyone can read them in DevTools. Secret keys go server-side; the frontend calls your backend, your backend calls the API. (3) Treating 401 and 403 the same — different fixes, different user messages. Confusing them is a common UX bug. (4) Not handling rate limits (429) — the API will start refusing requests. Read the `Retry-After` header and back off, or pre-throttle on your side. (5) Sending JSON without `Content-Type: application/json` — the server may parse the body as form-encoded or ignore it entirely, and return a confusing 400. Always set the header when you send a JSON body.

💡 Go deeper: designing your own REST APIs

This lesson is about consuming APIs from the client side. The flip side, designing and building them, is its own discipline: resource naming, versioning, pagination, idempotency, status-code contracts, authentication, and documentation. When you are ready to build the server instead of just calling it, the Programming Languages > REST APIs subtrack covers it from first principles, and the Node.js subtrack builds a full CRUD API end to end.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←JavaScript and the DOM
Back to Web Development
TypeScript Fundamentals→