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.