Server requests: fetch
Websites constantly exchange data with a server: they load products, send comments, check a login. Browsers provide the fetch() function for this. It sends an HTTP request — a message to the server at an address (URL) — and returns a promise with the response.
This site's sandbox has no network access, so examples with fetch() cannot run here. A response object can be created by hand, though — and that is how we will practise.
The first request
fetch() takes an address and returns a promise. Waiting for it with await gives you the response object:
const response = await fetch('https://api.example.com/users/1');
console.log(response.status); // 200A request without extra settings is called GET — it asks the server to send data.
The response object
A server response is an object of the Response class. You can also create one by hand, without a network: the first argument is the response body, the second is the settings:
const response = new Response('Hello', { status: 200 });
console.log(response.status); // 200
console.log(response.ok); // truestatus is the response code: 200 means "success", 404 "not found", 500 "server error". ok is true for codes from 200 to 299.
Reading JSON
Most often the server sends data in JSON format. The json() method turns the response body into an object. It is asynchronous too, so it needs an await:
const response = new Response('{"name": "Anna", "age": 28}');
const user = await response.json();
console.log(user.name); // AnnaFor plain text there is the text() method. A response body can be read only once.
Checking the status
fetch() rejects its promise only on a network failure. A 404 or 500 response counts as successfully received, so you check the status yourself:
async function loadUser(id) {
const response = await fetch(`https://api.example.com/users/${id}`);
if (!response.ok) {
throw new Error(`Error ${response.status}`);
}
return response.json();
}Sending data
To send data, pass settings as the second argument: the POST method, a header with the data type, and the request body itself as a JSON string:
const response = await fetch('https://api.example.com/comments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ author: 'Oleg', text: 'Great article!' }),
});The Content-Type header tells the server that the body contains JSON.
Handling errors
A request can fail: the internet drops, the server is down, an error code comes back. The whole request is wrapped in try...catch so that the user sees a clear message:
try {
const response = await fetch('https://api.example.com/users/7');
if (!response.ok) {
throw new Error(`Error ${response.status}`);
}
const user = await response.json();
console.log(user.name);
} catch (error) {
console.log(`Could not load: ${error.message}`);
}Common mistake
Forgetting await before response.json(). The method returns a promise, and a promise has no name field:
const response = new Response('{"name": "Anna"}');
const user = response.json();
console.log(user.name); // undefinedThe correct form is const user = await response.json(). Both fetch() and json() need their own await.