← Back to JavaScript Course | Chapter 9: Async & Web APIs | Lesson 13 of 26

JS AJAX Request

Beyond a simple GET, an AJAX request often needs to carry data to the server -- query parameters for filtering, a JSON body for creating a record, custom headers for authentication -- and configuring these correctly on the request is essential for it to be understood and processed properly by the server.

Passing Data via Query Parameters

For a GET request, data is typically passed as query parameters appended to the URL after a ? -- like /search?term=widgets&limit=10 -- which the server reads and parses from the incoming request's URL.

Note: Use URLSearchParams to build a query string safely rather than manually concatenating strings with & and =, which is easy to get wrong.

Warning: A raw, un-encoded value containing an & or = character inserted directly into a query string will corrupt the URL's structure.

Example: Passing Data via Query Parameters

javascript
const term = "widgets";
const limit = 10;
fetch(`search.php?term=${term}&limit=${limit}`)
  .then(r => r.json())
  .then(data => console.log(data));

Sending a JSON Request Body

For POST, PUT, or PATCH requests, data is usually sent in the request body as JSON -- JSON.stringify() converts a JavaScript object into that JSON string, and the Content-Type: application/json header tells the server how to correctly parse the body it receives.

Note: Always pair JSON.stringify() in the body with a Content-Type: application/json header -- sending JSON without that header can cause some servers to misinterpret the body.

Warning: Forgetting to call JSON.stringify() and sending a raw JavaScript object directly as the body sends the unhelpful text "[object Object]" instead of actual JSON data.

Example: Sending a JSON Request Body

javascript
fetch("save.php", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Sam" }),
}).then(r => r.json()).then(data => console.log(data));

Sending Form Data

FormData is a built-in object that represents form-style data, including file uploads -- constructing one from an actual <form> element (or manually appending fields) and passing it directly as a fetch body sends it with the correct multipart/form-data encoding automatically, no manual Content-Type header needed.

Note: Let the browser set the Content-Type header automatically when sending FormData -- setting it manually can actually break the request by omitting the required boundary parameter.

Warning: FormData is required (rather than JSON) whenever a request needs to include an actual file upload, since JSON cannot represent binary file data.

Example: Sending Form Data

javascript
const formData = new FormData();
formData.append("name", "Sam");
fetch("upload.php", { method: "POST", body: formData })
  .then(r => r.json())
  .then(data => console.log(data));

Setting Custom Request Headers

The headers option (in fetch) or .setRequestHeader() (in XMLHttpRequest) attaches additional metadata to a request -- most commonly an Authorization header carrying an API token, letting the server verify the request came from an authenticated user.

Note: Store sensitive tokens (like an API key) outside your client-side JavaScript source when possible, since anything shipped to the browser is visible to anyone inspecting the page.

Warning: Certain headers (like Origin or Host) are protected and cannot be set manually by JavaScript for security reasons, no matter how they are specified.

Example: Setting Custom Request Headers

javascript
fetch("data.php", {
  headers: { "Authorization": "Bearer sample-token" },
}).then(r => r.json()).then(data => console.log(data));

Choosing an HTTP Method

The method option specifies the HTTP verb for the request -- GET for reading data (the default), POST for creating something new, PUT or PATCH for updating, and DELETE for removing -- matching the method to the operation's actual meaning helps servers and any caching layers behave correctly.

Note: Match your request's method to its actual semantic purpose (GET for reads, POST for creates, and so on), rather than defaulting to GET or POST for everything.

Warning: Browsers and proxies may cache GET requests aggressively -- using GET for an operation that actually changes server state can produce confusing, inconsistent caching behavior.

Example: Choosing an HTTP Method

javascript
fetch("delete.php", { method: "DELETE" }).then(r => console.log(r.status));
fetch("update.php", { method: "PUT" }).then(r => console.log(r.status));
Common Mistakes
  1. Forgetting to set the Content-Type header to match the actual format of the data being sent, causing the server to misinterpret or reject the request body.
  2. URL-encoding query parameters incorrectly (or not at all), which can break the URL if a value contains special characters like & or spaces.
  3. Sending a request body on a GET request, which is against HTTP convention and often ignored or rejected by servers and some HTTP client implementations.
Chapter Summary
  • GET requests pass data via URL query parameters; POST/PUT requests typically pass data in the request body.
  • The Content-Type header tells the server how to interpret the request body's format (JSON, form-encoded, etc.).
  • encodeURIComponent() safely escapes special characters in a value before it is inserted into a URL.
Browser Support

Configuring requests with headers, query parameters, and a body is supported identically via fetch and XMLHttpRequest in every modern browser.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.