Fetch Basics
The Fetch API is the modern way to make HTTP requests. It replaces XMLHttpRequest with a clean Promise-based interface.
// GET request:
const response = await fetch("https://api.example.com/users");
if (!response.ok) throw new Error("HTTP " + response.status);
const users = await response.json();
// response.json() parses body as JSON
// response.text() for plain text
// response.blob() for files/images
// POST with JSON body:
const newUser = await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Alice", email: "alice@example.com" })
}).then(r => r.json());
// PUT, PATCH, DELETE:
await fetch("/api/users/1", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Updated Alice" })
});
await fetch("/api/users/1", { method: "DELETE" });
Common Patterns
// Reusable API client:
const api = {
baseUrl: "https://api.example.com",
async request(path, options = {}) {
const url = this.baseUrl + path;
const defaults = {
headers: { "Content-Type": "application/json" }
};
const config = { ...defaults, ...options };
if (config.body && typeof config.body === "object") {
config.body = JSON.stringify(config.body);
}
const response = await fetch(url, config);
if (!response.ok) throw new Error("HTTP " + response.status);
return response.json();
},
get: function(path) { return this.request(path); },
post: function(path, data) { return this.request(path, { method: "POST", body: data }); },
patch: function(path, data) { return this.request(path, { method: "PATCH", body: data }); },
delete: function(path) { return this.request(path, { method: "DELETE" }); }
};
// Abort long requests:
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
const response = await fetch("/api/slow", { signal: controller.signal });
// Upload files:
const formData = new FormData();
formData.append("file", fileInput.files[0]);
await fetch("/api/upload", { method: "POST", body: formData });
// Don't set Content-Type header - browser sets it with boundary
⚡ Key Takeaways
- fetch() never throws for HTTP errors (404, 500) — always check response.ok
- Set Content-Type: application/json header for JSON POST/PATCH requests
- For file uploads, use FormData without manually setting Content-Type
- AbortController cancels in-flight requests — great for timeouts
- Build a reusable API client to avoid repetition
🎯 Practice Exercises
EXERCISE 1
Build a complete CRUD client for https://jsonplaceholder.typicode.com/posts — get all, get one, create, update, delete. Handle all HTTP errors gracefully.