plainJS

Functions / Ajax

Send Ajax GET and POST requests

jQuery $.ajax(), $.get(), $.post(), $.getJSON()

In short

Use fetch(). It returns a promise for a Response; read the body with response.json() or response.text(), which are asynchronous too12. Check response.ok first: a 404 does not reject the promise, only a network failure does12. fetch has been available across browsers since March 20171.

  • GET JSON: const data = await (await fetch(url)).json(), after the ok check2
  • POST JSON: method: "POST", a Content-Type: application/json header, body: JSON.stringify(obj)2
  • A timeout is signal: AbortSignal.timeout(ms); cancelling is an AbortController24

The answer: GET

js
async function getJSON(url) {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`Response status: ${response.status}`);
  }
  return response.json();
}

const item = await getJSON("https://example.test/api/items/1");
console.log(item.title);   // "hello"

fetch() starts the request and resolves to a Response as soon as the headers are in1. The body is read by a second asynchronous call: json(), text(), blob(), formData() or arrayBuffer(), and json() throws if the body is not valid JSON2. The ok property is true for a status from 200 to 2993.

The answer: POST

js
async function postJSON(url, payload) {
  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });
  if (!response.ok) {
    throw new Error(`Response status: ${response.status}`);
  }
  return response.json();
}

const saved = await postJSON("https://example.test/api/items", { p1: 1, p2: "Hello World" });
console.log(saved.received.p2);   // "Hello World"

The Content-Type header tells the server the format of the body; set headers through the headers option as a plain object2. To send a form the way a browser would, pass a FormData object as the body and set no Content-Type at all; the browser writes the multipart header itself. FormData, URLSearchParams, a string, a Blob and a File are all accepted body types2.

htmlthe page
<form id="signup"><input name="email" value="[email protected]"></form>
js
const form = document.querySelector("#signup");
const response = await fetch("https://example.test/api/signup", {
  method: "POST",
  body: new FormData(form),
});
console.log(response.status);   // 200
Advertisement

In jQuery

jsjQuery
$.getJSON("https://example.test/api/items/1", function (item) {
  console.log(item.title);
});

$.post("https://example.test/api/items", { p1: 1, p2: "Hello World" }, function (saved) {
  console.log(saved.method);
});

jQuery’s $.ajax() and its shorthands guess the response type from the MIME type unless dataType says otherwise, always add the header X-Requested-With: XMLHttpRequest, and return a jqXHR object that has implemented the Promise interface since jQuery 1.55.

Browser support fetch() is Baseline widely available: across browsers since March 20171. AbortSignal.timeout(), used below, is widely available since April 20244. The 2015 version of this page used XMLHttpRequest with an ActiveXObject fallback for Internet Explorer 6; none of that is needed.

Differs from jQuery A 404 or a 500 does not reject the fetch() promise; only a badly formed URL or a network error does, so the ok check is not optional12. Nothing is parsed for you: jQuery guesses JSON from the MIME type5, fetch hands you a body you read once with json()2. No X-Requested-With header is sent; jQuery always adds one5, and a server that detects Ajax by it needs the header set in headers. A body can be read only once; call response.clone() before the first read if you need it twice2.

Timeouts and cancelling

js
try {
  const response = await fetch("https://example.test/api/slow", { signal: AbortSignal.timeout(500) });
  console.log(response.status);
} catch (err) {
  if (err.name === "TimeoutError") console.log("gave up after 500 ms");
  else throw err;
}

AbortSignal.timeout(ms) returns a signal that aborts on its own after the given time, with a TimeoutError4. For a cancel button, create an AbortController, pass its signal, and call controller.abort(); the promise then rejects with an AbortError2.

js
const controller = new AbortController();
const request = fetch("https://example.test/api/items", { signal: controller.signal });
controller.abort();
try {
  await request;
} catch (err) {
  console.log(err.name);   // "AbortError"
}

Security Never build a URL or a body from user input without encoding it: put query values through URLSearchParams and send JSON through JSON.stringify(), as above. Credentials for another origin are not sent unless you ask, and that is the right default.

Sources

  1. Window: fetch() method, MDN (accessed 2026-10-29)
  2. Using the Fetch API, MDN (accessed 2026-10-29)
  3. Response: ok property, MDN (accessed 2026-10-29)
  4. AbortSignal: timeout() static method, MDN (accessed 2026-10-29)
  5. jQuery.ajax(), jQuery API documentation (accessed 2026-10-29)

Last reviewed 2026-10-30. Tested in Chromium 148, 2026-10-29 by the snippet harness.