Loading...
Loading...
Connect your app to the world. CRUD, auth, pagination, and real patterns.
Browsers and servers spend most of their time waiting — for network responses, timers, and user input. Async JavaScript lets your program stay responsive while work happens in the background using callbacks, Promises, and async/await.
Learn Working with APIs in JavaScript — covering REST Basics, CRUD Operations, Authentication, Pagination with interactive visual examples and step-by-step explanations.
Synchronous code runs one line at a time. But real applications wait for network requests, file reads, and timers. Async JavaScript lets your program keep running while that work happens in the background — without freezing the UI.
This module covers the full async story: callbacks, Promises, async/await, and the Fetch API. Visual timelines show when tasks enter the queue, when they resolve, and why async/await is syntactic sugar over Promises — not magic.
Understanding working with apis is essential for every JavaScript developer. It shows up in frontend UI code, backend APIs, and framework internals — and getting it wrong leads to bugs that are hard to trace. This chapter builds intuition with visuals so the behavior sticks.
RESTful APIs use HTTP methods on URL endpoints.
| Method | Purpose | Example |
|---|---|---|
| GET | Read | GET /api/users |
| POST | Create | POST /api/users |
| PUT | Replace | PUT /api/users/1 |
| PATCH | Update | PATCH /api/users/1 |
| DELETE | Delete | DELETE /api/users/1 |
// REST URL patterns: // Collection: /api/users (list of users) // Resource: /api/users/123 (single user) // Nested: /api/users/123/posts (user's posts) // Filtered: /api/users?role=admin&limit=10 // A REST API response typically looks like: { "data": [...], "meta": { "total": 100, "page": 1 } }
Create, Read, Update, Delete — the four fundamental operations.
const API_URL = "https://api.example.com"; // CREATE — add a new resource: async function createUser(userData) { const res = await fetch(`${API_URL}/users`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(userData), }); if (!res.ok) throw new Error(`Create failed: ${res.status}`); return res.json(); // { id: 4, name: "Alice", ... } } // READ — get resources: async function getUsers() { const res = await fetch(`${API_URL}/users`); if (!res.ok) throw new Error(`Fetch failed: ${res.status}`); return res.json(); } async function getUser(id) { const res = await fetch(`${API_URL}/users/${id}`); if (!res.ok) throw new Error(`User not found`); return res.json(); }
// UPDATE — modify existing resource: async function updateUser(id, updates) { const res = await fetch(`${API_URL}/users/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(updates), }); if (!res.ok) throw new Error(`Update failed: ${res.status}`); return res.json(); } // DELETE — remove a resource: async function deleteUser(id) { const res = await fetch(`${API_URL}/users/${id}`, { method: "DELETE", }); if (!res.ok) throw new Error(`Delete failed: ${res.status}`); return res.status === 204 ? null : res.json(); }
Prove who you are to the API.
// Method 1: Bearer Token (most common) async function fetchProtected(url, token) { const res = await fetch(url, { headers: { "Authorization": `Bearer ${token}`, }, }); if (res.status === 401) { // Token expired — refresh it const newToken = await refreshToken(); return fetchProtected(url, newToken); } return res.json(); } // Method 2: API Key (simpler) const res = await fetch(`${API_URL}/data?api_key=${API_KEY}`); // or in headers: const res2 = await fetch(url, { headers: { "X-API-Key": API_KEY }, });
// Login flow: async function login(email, password) { const res = await fetch("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, password }), }); if (!res.ok) throw new Error("Invalid credentials"); const { token, refreshToken } = await res.json(); // Store securely (httpOnly cookie is best) localStorage.setItem("token", token); return token; }
Handle large datasets by loading in pages.
// Offset-based pagination: async function getUsers(page = 1, limit = 20) { const res = await fetch( `/api/users?page=${page}&limit=${limit}` ); const data = await res.json(); // { users: [...], total: 150, page: 1, pages: 8 } return data; } // Load all pages: async function getAllUsers() { const allUsers = []; let page = 1; let hasMore = true; while (hasMore) { const { users, pages } = await getUsers(page); allUsers.push(...users); hasMore = page < pages; page++; } return allUsers; }
// Cursor-based pagination (better for real-time data): async function fetchFeed(cursor = null) { const url = cursor ? `/api/feed?after=${cursor}&limit=20` : "/api/feed?limit=20"; const res = await fetch(url); const { items, nextCursor } = await res.json(); return { items, nextCursor }; // nextCursor = null means no more items } // Infinite scroll: let cursor = null; async function loadMore() { const { items, nextCursor } = await fetchFeed(cursor); cursor = nextCursor; appendToList(items); if (!nextCursor) hideLoadMoreButton(); }
Wrap fetch in a reusable utility.
// A simple, reusable API client: class ApiClient { constructor(baseUrl, token = null) { this.baseUrl = baseUrl; this.token = token; } async request(endpoint, options = {}) { const url = `${this.baseUrl}${endpoint}`; const headers = { "Content-Type": "application/json", ...(this.token && { Authorization: `Bearer ${this.token}` }), ...options.headers, }; const res = await fetch(url, { ...options, headers }); if (!res.ok) { const error = await res.json().catch(() => ({})); throw new Error(error.message || `HTTP ${res.status}`); } if (res.status === 204) return null; return res.json(); } get(endpoint) { return this.request(endpoint); } post(endpoint, data) { return this.request(endpoint, { method: "POST", body: JSON.stringify(data), }); } patch(endpoint, data) { return this.request(endpoint, { method: "PATCH", body: JSON.stringify(data), }); } delete(endpoint) { return this.request(endpoint, { method: "DELETE" }); } }
// Usage: const api = new ApiClient("https://api.example.com", token); const users = await api.get("/users"); const newUser = await api.post("/users", { name: "Alice" }); await api.patch(`/users/${newUser.id}`, { name: "Bob" }); await api.delete(`/users/${newUser.id}`);
Common questions about working with apis.