AiTechWorlds
AiTechWorlds
University learning companion
JavaScript Complete 2026 · Fetch API & Working with REST APIs
A feature looks correct on a developer’s large monitor but fails on a slow connection and a small screen. Use this topic to inspect structure, state, loading/error behaviour, accessibility and the user journey—not just the happy path.
Use this course-level map to place “Fetch API & Working with REST APIs” in the larger system. It complements—not replaces—a topic-specific worked diagram.
The Fetch API is JavaScript's built in way to make HTTP requests no libraries required. It returns Promises, works seamlessly with async/await, and handles everything from simple data fetching to file uploads and streaming responses.
// Returns a Promise that resolves to a Response object
const response = await fetch("https://api.example.com/users");
// Response has status info
response.status; // 200, 404, 500, etc.
response.ok; // true if status is 200-299
response.headers; // Headers object
// Parse the body (also returns a Promise)
const data = await response.json(); // parse as JSON
const text = await response.text(); // parse as plain text
const blob = await response.blob(); // parse as binaryfetch only rejects on network errors. A 404 or 500 response resolves successfully you must check response.ok:
async function getUser(id) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
// Try to get error details from the response body
const error = await response.json().catch(() => ({ message: response.statusText }));
throw new Error(error.message ?? `HTTP ${response.status}`);
}
return response.json();
}
// Usage
try {
const user = await getUser(42);
displayUser(user);
} catch (err) {
if (err.message.includes("404")) {
showNotFound();
} else {
showError(err.message);
}
}const BASE_URL = "https://api.example.com";
// POST — create a resource
async function createUser(userData) {
const response = await fetch(`${BASE_URL}/users`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${getToken()}`
},
body: JSON.stringify(userData)
});
if (!response.ok) throw new Error("Failed to create user");
return response.json();
}
// PUT — replace a resource
async function updateUser(id, data) {
const response = await fetch(`${BASE_URL}/users/${id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
if (!response.ok) throw new Error("Failed to update");
return response.json();
}
// PATCH — partial update
async function patchUser(id, changes) {
const response = await fetch(`${BASE_URL}/users/${id}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(changes)
});
if (!response.ok) throw new Error("Failed to patch");
return response.json();
}
// DELETE
async function deleteUser(id) {
const response = await fetch(`${BASE_URL}/users/${id}`, {
method: "DELETE",
headers: { "Authorization": `Bearer ${getToken()}` }
});
if (!response.ok) throw new Error("Failed to delete");
// DELETE often returns 204 No Content (no body to parse)
}Wrap fetch in a class for reuse:
class ApiClient {
constructor(baseUrl, getToken) {
this.baseUrl = baseUrl;
this.getToken = getToken;
}
async request(path, options = {}) {
const url = `${this.baseUrl}${path}`;
const token = this.getToken?.();
const response = await fetch(url, {
...options,
headers: {
"Content-Type": "application/json",
...(token && { "Authorization": `Bearer ${token}` }),
...options.headers
}
});
if (response.status === 204) return null; // No Content
const data = await response.json().catch(() => null);
if (!response.ok) {
const message = data?.message ?? `HTTP ${response.status}`;
const error = new Error(message);
error.status = response.status;
error.data = data;
throw error;
}
return data;
}
get(path, params = {}) {
const query = new URLSearchParams(params).toString();
return this.request(`${path}${query ? `?${query}` : ""}`);
}
post(path, body) {
return this.request(path, { method: "POST", body: JSON.stringify(body) });
}
put(path, body) {
return this.request(path, { method: "PUT", body: JSON.stringify(body) });
}
patch(path, body) {
return this.request(path, { method: "PATCH", body: JSON.stringify(body) });
}
delete(path) {
return this.request(path, { method: "DELETE" });
}
}
// Usage
const api = new ApiClient("https://api.example.com", () => localStorage.getItem("token"));
const users = await api.get("/users", { page: 1, limit: 20 });
const newUser = await api.post("/users", { name: "Alice", email: "alice@example.com" });
await api.delete(`/users/${id}`);// URLSearchParams for clean query string building
const params = new URLSearchParams({
page: 1,
limit: 20,
sort: "name",
filter: "active"
});
params.toString(); // "page=1&limit=20&sort=name&filter=active"
fetch(`/api/users?${params}`);
// Append multiple values for same key
const tags = new URLSearchParams();
["javascript", "react", "nextjs"].forEach(tag => tags.append("tag", tag));
// "tag=javascript&tag=react&tag=nextjs"// FormData for multipart/form-data uploads
const fileInput = document.querySelector("#file");
async function uploadFile(file) {
const formData = new FormData();
formData.append("file", file);
formData.append("category", "avatar");
// Don't set Content-Type header — browser sets it with boundary
const response = await fetch("/api/upload", {
method: "POST",
body: formData
});
if (!response.ok) throw new Error("Upload failed");
return response.json();
}// Cancel a request in progress
const controller = new AbortController();
// Cancel if user navigates away
setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch("/api/slow-endpoint", {
signal: controller.signal
});
const data = await response.json();
} catch (err) {
if (err.name === "AbortError") {
console.log("Request cancelled");
} else {
throw err;
}
}
// React pattern: cancel on component unmount
useEffect(() => {
const controller = new AbortController();
fetch("/api/data", { signal: controller.signal })
.then(r => r.json())
.then(setData)
.catch(err => {
if (err.name !== "AbortError") setError(err);
});
return () => controller.abort(); // cleanup
}, []);Next lesson: Classes & Prototype Chain understanding JavaScript's object oriented system.
University learning companion
JavaScript Complete 2026 · Fetch API & Working with REST APIs
Complete the steps without looking at the answer first; record evidence rather than only a final result.
These are primary or established learning references for this subject. Check the relevant chapter or specification for the exact topic and version.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises