AJAX in JavaScript

AJAX stands for Asynchronous JavaScript and XML. But don't let the name confuse you — it's not really about XML anymore. AJAX is simply a way to load data from a server without refreshing the whole page.

Think about Gmail or Twitter. When you get a new email or tweet, the page doesn't fully reload — just that small part updates. That's AJAX at work. Your browser quietly goes to the server, grabs the new data, and updates only the part of the page that needs it.

Before AJAX, every time you needed new data, you had to reload the entire page. That was slow and annoying. AJAX changed that by letting JavaScript talk to the server in the background while you keep browsing.

  • Load new content without a page refresh
  • Send data to a server (like a form submission) without navigating away
  • Check for updates in the background (like live notifications)
Quick history: AJAX was popularized around 2005 by Google Maps, which was blowing people's minds by loading map tiles without a page reload. The "XML" part in the name is old — today most apps use JSON instead.

Every time you open a website, two things are involved — a client and a server.

The client is your browser (Chrome, Firefox, Safari). It's the thing asking for stuff. The server is a computer somewhere else that has the data and sends it back to you.

Think of it like sending a message on WhatsApp. Your phone (the client) sends a message to WhatsApp's server. The server receives it, processes it, and delivers it to the other person's device. Your phone never connects directly to theirs - the server is always in the middle, handling the exchange.

  • Client — your browser, makes requests, shows the result
  • Server — a computer that receives requests and sends back data
  • Network — the internet connection between them

When you use AJAX, JavaScript on the client side sends a request to the server, the server processes it and sends back a response, and then JavaScript updates the page with the new data — all without you having to click a refresh button.

Good to know: The server doesn't know or care what browser you're using. It just receives a request and sends back data. How that data is shown is entirely up to your JavaScript code on the client side.

Every conversation between a client and server happens in two parts: a request and a response.

The request is what the client sends. It includes:

  • Method — what you want to do (GET, POST, PUT, DELETE)
  • URL — where to send the request (e.g. https://api.example.com/users)
  • Headers — extra info like content type or authentication tokens
  • Body — the actual data you're sending (only for POST/PUT)

The response is what the server sends back. It includes:

  • Status code — a number that tells you if the request worked (e.g. 200 = OK, 404 = Not Found, 500 = Server Error)
  • Headers — info about the response (like content type)
  • Body — the actual data (usually JSON)

The most common HTTP methods you'll use are:

  • GET — fetch data (read-only, no body needed)
  • POST — send new data to the server (like creating a user)
  • PUT — update existing data
  • DELETE — remove data
Status codes to remember: 200 (OK), 201 (Created), 400 (Bad Request), 401 (Unauthorized), 403 (Forbidden), 404 (Not Found), 500 (Internal Server Error).

API stands for Application Programming Interface. That sounds complicated, but the idea is simple — an API is just a way for two programs to talk to each other.

When you're building a web app, you often need data from somewhere else — weather info, user data, product listings, etc. Instead of building all that yourself, you can use an API that someone else built. You ask for the data, and they give it to you in a format your code can understand.

Think of an API like a USB port. The port is a standardized interface - any compatible device can plug in and communicate. You don't need to know how the device was built internally; you just need to know the standard. Web APIs work the same way: they define a standard set of URLs and data formats, so your code can connect without knowing anything about how the server works internally.

javascript

// A public API that returns fake user data for testing
// URL: https://jsonplaceholder.typicode.com/users/1
// Response (JSON):
// {
//   "id": 1,
//   "name": "Leanne Graham",
//   "email": "Sincere@april.biz",
//   "phone": "1-770-736-0988"
// }

APIs typically return data in JSON format (JavaScript Object Notation). JSON looks exactly like a JavaScript object, so it's very easy to work with in JavaScript.

Examples of popular public APIs you can try: JSONPlaceholder (fake data for testing), OpenWeatherMap (weather data), GitHub API (repository and user info).

Web API vs JavaScript API: "API" can mean two things. A Web API is a server you talk to over the internet. A JavaScript API is a built-in browser feature like the DOM or Fetch. In this tutorial, we're talking about Web APIs — servers you talk to with AJAX.

REST stands for Representational State Transfer. It's a set of rules that developers follow when designing APIs so that they're predictable and easy to use.

The core idea is simple: each URL represents a resource (a thing), and you use different HTTP methods to do different things to that resource.

text

// RESTful API examples for a "users" resource:

GET    /users          ? get all users
GET    /users/1        ? get user with id 1
POST   /users          ? create a new user
PUT    /users/1        ? update user with id 1
DELETE /users/1        ? delete user with id 1

See how clean that is? The URL tells you what you're working with (users), and the HTTP method tells you what you're doing to it (reading, creating, updating, deleting). This style is called RESTful.

Key rules that make an API "RESTful":

  • Stateless — each request must contain all the information needed. The server doesn't remember your previous requests.
  • Uniform interface — use standard HTTP methods (GET, POST, PUT, DELETE) consistently
  • Resource-based URLs — URLs should be nouns, not verbs. Use /users not /getUsers
  • Use HTTP status codes — 200 for success, 404 for not found, etc.
Most APIs you'll use are REST APIs. When you see a tutorial saying "call the API" or "make an API request", they almost always mean a RESTful HTTP request over the internet.

CORS stands for Cross-Origin Resource Sharing. If you've ever seen an error in the console that says something like "has been blocked by CORS policy", this is what it's about.

Here's the problem CORS solves: by default, your browser will not allow JavaScript on one website to request data from a different website. This is called the Same-Origin Policy and it exists for security reasons — to stop malicious sites from stealing your data.

For example, if your website is on myapp.com and you try to fetch data from api.someothersite.com, the browser will block it by default. That's CORS kicking in.

The good news is that servers can opt in to allow requests from other origins. They do this by sending back special headers in their response:

text

// A server response header that allows any origin to access the API:
Access-Control-Allow-Origin: *

// Or allow only a specific site:
Access-Control-Allow-Origin: https://myapp.com

If the server does not include these headers, your browser will block the response even if the request went through. The error is thrown by the browser, not the server.

As a frontend developer, you usually can't fix CORS errors yourself — the server has to allow your origin. But during development, there are a few common workarounds:

  • Use a proxy (your dev server forwards the request to avoid cross-origin issues)
  • Ask the backend developer to add the right CORS headers
  • Use a public API that already allows cross-origin requests (like JSONPlaceholder)
CORS is a browser thing. Tools like Postman or curl don't have the same-origin policy, so they will work fine even when your browser throws a CORS error. The restriction only applies when JavaScript in a browser tries to make the request.

XMLHttpRequest (often shortened to XHR) is the original way JavaScript talks to servers. It was introduced in the early 2000s and was the foundation of AJAX for many years. Even though modern code uses the Fetch API now, it's worth knowing how XHR works because you'll see it in older codebases.

Here's the basic pattern — it's a bit verbose compared to modern approaches:

javascript

// Step 1: Create a new XMLHttpRequest object
const xhr = new XMLHttpRequest();

// Step 2: Configure the request (method + URL)
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1");

// Step 3: Define what happens when the response arrives
xhr.onload = function () {
  if (xhr.status === 200) {
    const data = JSON.parse(xhr.responseText);
    console.log(data.title); // sunt aut facere repellat...
  } else {
    console.error("Request failed: " + xhr.status);
  }
};

// Step 4: Send the request
xhr.send();

The key property is readyState — it tells you what stage the request is at:

  • 0 — Not sent yet (UNSENT)
  • 1 — Connection opened (OPENED)
  • 2 — Request sent, headers received (HEADERS_RECEIVED)
  • 3 — Downloading response (LOADING)
  • 4 — Done (DONE)

javascript

const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1");

// onreadystatechange fires every time readyState changes
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
    const post = JSON.parse(xhr.responseText);
    console.log(post.title);
  }
};

xhr.send();
XHR vs Fetch: XHR is event-based and a bit clunky to read. The Fetch API (covered in the next tutorial) does the same thing with a much cleaner, Promise-based syntax. In new code, prefer Fetch. But knowing XHR means you can understand and maintain older projects.

Let's put it all together and make a real API call with XMLHttpRequest. We'll use JSONPlaceholder — a free, public API that returns fake data, perfect for learning and testing.

javascript

// GET request - fetch a list of posts
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts");

xhr.onload = function () {
  if (xhr.status === 200) {
    const posts = JSON.parse(xhr.responseText);
    console.log("Total posts:", posts.length); // 100
    console.log("First post title:", posts[0].title);
  }
};

xhr.send();

You can also send a POST request to create data. You need to set the Content-Type header and pass the data in the body:

javascript

// POST request - send new data
const xhr = new XMLHttpRequest();
xhr.open("POST", "https://jsonplaceholder.typicode.com/posts");

// Tell the server we're sending JSON
xhr.setRequestHeader("Content-Type", "application/json");

xhr.onload = function () {
  if (xhr.status === 201) {
    const newPost = JSON.parse(xhr.responseText);
    console.log("Created post with id:", newPost.id); // 101
  }
};

const postData = {
  title: "My new post",
  body: "This is the content",
  userId: 1
};

xhr.send(JSON.stringify(postData));
Tip: Always call JSON.stringify() before sending an object in the request body, and JSON.parse() after receiving the response text. That's how you convert between JavaScript objects and JSON strings.

Once your AJAX request completes, you need to handle what comes back. There are three things that can happen: success, a server error, or a network failure. Good code handles all three.

javascript

const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/users/1");

// Called when the request completes (success or server error)
xhr.onload = function () {
  if (xhr.status >= 200 && xhr.status < 300) {
    // Success
    const user = JSON.parse(xhr.responseText);
    console.log("Name:", user.name);
    console.log("Email:", user.email);
  } else {
    // Server returned an error (404, 500, etc.)
    console.error("Server error:", xhr.status, xhr.statusText);
  }
};

// Called only if the network itself failed (no internet, bad URL, etc.)
xhr.onerror = function () {
  console.error("Network error - request could not be sent");
};

xhr.send();

You can also show a loading state while the request is in progress using the onprogress event:

javascript

const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/photos"); // ~5000 items

// Show loading feedback
document.getElementById("status").textContent = "Loading...";

xhr.onload = function () {
  document.getElementById("status").textContent = "Done!";
  const photos = JSON.parse(xhr.responseText);
  console.log("Loaded photos:", photos.length);
};

xhr.onerror = function () {
  document.getElementById("status").textContent = "Failed to load.";
};

xhr.send();

A few important properties to know when reading a response:

  • xhr.status — the HTTP status code (200, 404, 500, etc.)
  • xhr.statusText — the status message ("OK", "Not Found", etc.)
  • xhr.responseText — the raw response body as a string
  • xhr.responseType — set this to "json" and the browser parses it for you automatically

javascript

// Using responseType "json" - no need to JSON.parse manually
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/users/1");
xhr.responseType = "json"; // browser parses JSON automatically

xhr.onload = function () {
  if (xhr.status === 200) {
    // xhr.response is already a JavaScript object
    console.log(xhr.response.name);  // Leanne Graham
    console.log(xhr.response.email); // Sincere@april.biz
  }
};

xhr.send();
Always handle errors. A lot of beginners only write the happy path. In real projects, things go wrong — the server goes down, the user has no internet, the URL changes. Make sure your code has an onerror handler and checks the status code.
  • AJAX lets you load or send data in the background without refreshing the page
  • Every web interaction involves a client (your browser) and a server (a computer somewhere else)
  • A request includes a method, URL, headers, and optionally a body. A response includes a status code, headers, and a body
  • Common HTTP methods: GET (read), POST (create), PUT (update), DELETE (remove)
  • An API is a server that your app can talk to over the internet to get or send data
  • REST is a set of conventions for building APIs using HTTP methods and resource-based URLs
  • CORS is a browser security policy. The server must include the right headers to allow requests from other origins
  • XMLHttpRequest (XHR) is the original AJAX tool - event-based and verbose, but still found in older codebases
  • Always handle both success and error cases in your response handlers

What's next? Now that you understand how AJAX and the request/response cycle work, learn the modern way to do it in the Fetch API tutorial.

  • What does AJAX stand for, and what problem does it solve?
  • What is the difference between a client and a server?
  • What are the main parts of an HTTP request?
  • What do HTTP status codes like 200, 404, and 500 mean?
  • What is an API? How is it different from a regular website?
  • What is REST? What makes an API "RESTful"?
  • What is CORS and why does it exist?
  • What triggers a CORS error? Who is responsible for fixing it?
  • What is XMLHttpRequest and how do you use it to make a GET request?
  • What does readyState === 4 mean in XHR?
  • What is the difference between onload and onerror in XHR?
  • How is XHR different from the Fetch API?
Async & Await
Fetch API