The Evolution of API Calls in JavaScript
The ability to fetch data from a server without refreshing the page is what transformed the web from a collection of static documents into the interactive "Web 2.0" we use today.
1. The Early Days: XMLHTTPRequest (AJAX)
In the early 2000s, Microsoft introduced XMLHttpRequest (XHR). It was the first time developers could send and receive data after a page had loaded. This technique became known as AJAX (Asynchronous JavaScript and XML).
Characteristics:
- Uses a "callback" based system.
- Very verbose and difficult to read.
- Handling errors and multiple nested requests led to "Callback Hell."
// The "Old School" Way
// IE5–IE6 style (ActiveX)
var xhr = new ActiveXObject("Msxml2.XMLHTTP");
// or
var xhr = new ActiveXObject("Microsoft.XMLHTTP");
// Modern cross-browser (2006+)
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/users/123', true); // true = asynchronous
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
var data = JSON.parse(xhr.responseText);
console.log('Success:', data);
} else {
console.error('Request failed. Status:', xhr.status);
}
};
xhr.onerror = function () {
console.error('Network error');
};
xhr.send(); // actually sends the request
Pain points → lots of boilerplate, manual state checking, no promises.
2. The Library Era: jQuery AJAX
To solve the verbosity and browser inconsistency issues of the original XMLHttpRequest (XHR), libraries like jQuery became the industry standard. It simplified the syntax significantly and handled cross-browser compatibility behind the scenes.
Characteristics:
- Cleaner, more readable code: Much less boilerplate than raw XHR.
-
Simplified error handling: Integrated
successanderrorcallbacks. - Callback-based: Still relied on callbacks (until later versions introduced deferreds/promises).
// The "jQuery" Way
$.ajax({
url: '[https://api.example.com/data](https://api.example.com/data)',
method: 'GET',
success: function(data) {
console.log(data);
},
error: function(err) {
console.error("Something went wrong");
}
});
→ Huge productivity boost, but still callback-based.
3. Axios – Promise-based comfort (2014+)
Very popular bridge before Fetch was everywhere.
axios.get("/api/users")
.then(response => console.log(response.data))
.catch(error => console.error(error.response?.data));
axios.post("/api/login", { email, password }, {
headers: { Authorization: "Bearer token" }
});
Features like interceptors, auto JSON, timeout built-in made it win many codebases.
4. Fetch API – the native modern standard (2015 → now)
Promise-based, stream-aware, no extra library.
// Basic GET
fetch("https://api.example.com/data")
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then(data => console.log(data))
.catch(err => console.error(err));
// Modern async/await style (2017+)
async function getUsers() {
try {
const response = await fetch("/api/users", {
method: "GET",
headers: { "Accept": "application/json" },
credentials: "include" // cookies, etc.
});
if (!response.ok) {
throw new Error(`Error ${response.status}`);
}
const data = await response.json();
return data;
} catch (err) {
console.error("Fetch failed:", err);
}
}
Fetch improvements over XHR
- Promise-based → works beautifully with async/await
- Stream support (
response.bodyis ReadableStream) - Cleaner aborting (
AbortController) - No automatic JSON rejection on 404/500 → you must check
response.ok
Code Playground
Current status (2026)
- Fetch is the recommended native way in browsers (all modern browsers 100% support since ~2017–2018)
- Node.js made Fetch stable in v18 (2022) → v21+ it's the default
- Axios still widely used (especially in large codebases needing interceptors, better defaults)
- Raw XHR is considered legacy — only used for very specific low-level needs
Thanks for reading. Happy coding!!!
Top comments (0)