The Fetch API provides a JavaScript interface for accessing and manipulating parts of the protocol, such as requests and responses. It also provides a global fetch() method that provides an easy, logical way to fetch resources asynchronously across the network.
A basic fetch request looks like this:
async function getLogs() {
const response = await fetch("http://example.com/logs.json");
const logs = await response.json();
console.log(logs);
}
The fetch() method can optionally accept a second parameter, an init object that allows you to control a number of different settings.
//Example POST method implementation:
async function postData(url = "
", data = {}) {
//Default options are marked with *
const response = await fetch(url, {
method: "
POST ", //*GET, POST, PUT, DELETE, etc.
mode: "
cors ", //no-cors, *cors, same-origin
cache: "
no - cache ", //*default, no-cache, reload, force-cache, only-if-cached
credentials: "
same - origin ", //include, *same-origin, omit
headers: {
"
Content - Type ": "
application / json ",
//'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: "
follow ", //manual, *follow, error
referrerPolicy: "
no - referrer ", //no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data), //body data type must match "Content-Type" header
});
return response.json(); //parses JSON response into native JavaScript objects
To abort incomplete fetch() operations, use the AbortController and AbortSignal interfaces.
const controller = new AbortController();
const signal = controller.signal;
const url = "video.mp4";
const downloadBtn = document.querySelector("#download");
const abortBtn = document.querySelector("#abort");
downloadBtn.addEventListener("click", async () => {
try {
const response = await fetch(url, { signal });
console.log("Download complete", response);
} catch (error) {
console.error(``Download error: ${error.message}``);
}
});
abortBtn.addEventListener("click", () => {
controller.abort();
console.log("Download aborted");
});
To cause browsers to send a request with credentials included on both same-origin and cross-origin calls, add credentials: 'include' to the init object you pass to the fetch() method.
fetch("https://example.com", {
credentials: "include",
});
Use fetch() to POST JSON-encoded data.
async function postJSON(data) {
try {
const response = await fetch("https://example.com/profile", {
method: "POST", // or 'PUT'
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
const result = await response.json();
console.log("Success:", result);
} catch (error) {
console.error("Error:", error);
}
}
const data = { username: "example" };
postJSON(data);
Files can be uploaded using an HTML <input type='file' /> input element, FormData() and fetch().
async function upload(formData) {
try {
const response = await fetch("https://example.com/profile/avatar", {
method: "PUT",
body: formData,
});
const result = await response.json();
console.log("Success:", result);
} catch (error) {
console.error("Error:", error);
}
}
const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');
formData.append("username", "abc123");
formData.append("avatar", fileField.files[0]);
upload(formData);
Files can be uploaded using an HTML <input type='file' multiple /> input element, FormData() and fetch().
async function uploadMultiple(formData) {
try {
const response = await fetch("https://example.com/posts", {
method: "POST",
body: formData,
});
const result = await response.json();
console.log("Success:", result);
} catch (error) {
console.error("Error:", error);
}
}
const photos = document.querySelector('input[type="file"][multiple]');
const formData = new FormData();
formData.append("title", "My Vegas Vacation");
for (const [i, photo] of Array.from(photos.files).entries()) {
formData.append(`photos_${i}`, photo);
}
uploadMultiple(formData);
The chunks that are read from a response are not broken neatly at line boundaries and are Uint8Arrays, not strings. If you want to fetch a text file and process it line by line, it is up to you to handle these complications.
async function* makeTextFileLineIterator(fileURL) {
const utf8Decoder = new TextDecoder("utf-8");
const response = await fetch(fileURL);
const reader = response.body.getReader();
let { value: chunk, done: readerDone } = await reader.read();
chunk = chunk ? utf8Decoder.decode(chunk) : ";
const newline = /\\r?\\n/gm;
let startIndex = 0;
let result;
while (true) {
const result = newline.exec(chunk);
if (!result) {
if (readerDone) break;
const remainder = chunk.substr(startIndex);
({ value: chunk, done: readerDone } = await reader.read());
chunk = remainder + (chunk ? utf8Decoder.decode(chunk) : ");
startIndex = newline.lastIndex = 0;
continue;
}
yield chunk.substring(startIndex, result.index);
startIndex = newline.lastIndex;
}
if (startIndex < chunk.length) {
// Last line didn't end in a newline char
yield chunk.substr(startIndex);
}
}
async function run() {
for await (const line of makeTextFileLineIterator(urlOfFile)) {
processLine(line);
}
}
run();
A fetch() promise will reject with a TypeError when a network error is encountered or CORS is misconfigured on the server-side, although this usually means permission issues or similar — a 404 does not constitute a network error, for example.
async function fetchImage() {
try {
const response = await fetch("flowers.jpg");
if (!response.ok) {
throw new Error("Network response was not OK");
}
const myBlob = await response.blob();
myImage.src = URL.createObjectURL(myBlob);
} catch (error) {
console.error("There has been a problem with your fetch operation:", error);
}
}
Instead of passing a path to the resource you want to request into the fetch() call, you can create a request object using the Request() constructor, and pass that in as a fetch() method argument.
async function fetchImage(request) {
try {
const response = await fetch(request);
if (!response.ok) {
throw new Error("Network response was not OK");
}
const myBlob = await response.blob();
myImage.src = URL.createObjectURL(myBlob);
} catch (error) {
console.error("Error:", error);
}
}
const myHeaders = new Headers();
const myRequest = new Request("flowers.jpg", {
method: "GET",
headers: myHeaders,
mode: "cors",
cache: "default",
});
fetchImage(myRequest);
The Headers interface allows you to create your own headers object via the Headers() constructor. A headers object is a simple multi-map of names to values.
const content = "Hello World";
const myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");
The fetch specification differs from jQuery.ajax() in several significant ways. Here are some key differences:
The Fetch API is a powerful tool for making HTTP requests in JavaScript. It provides a cleaner and more flexible syntax compared to the older XMLHttpRequest. By understanding how to use Fetch, you can efficiently communicate with servers and handle responses.