HTTP requests with fetch
A server does not only answer requests — it sends them too: it fetches exchange rates, checks an address with an external service, posts a notification. Node.js has the same fetch() function as the browser for this, with nothing to install. You know how it works from the tutorial; here are the specifics of server code.
A GET request
Create the file scripts/check-blog.js, which requests your blog's post list. The server from the previous lessons must be running in another terminal window:
// scripts/check-blog.js
const response = await fetch('http://localhost:3000/posts');
const posts = await response.json();
console.log(`Posts in the blog: ${posts.length}`);node scripts/check-blog.js prints the number of posts. await works directly in the module, and response.json() parses the response body.
Checking the status
fetch() does not throw on 404 or 500 responses — it throws only when the server cannot be reached at all. You check the status yourself with response.ok:
// scripts/check-blog.js
const response = await fetch('http://localhost:3000/posts/999');
if (!response.ok) {
console.log(`Error: ${response.status}`);
} else {
console.log(await response.json());
}There is no post 999, so "Error: 404" is printed. response.ok is true for codes from 200 to 299.
Sending JSON
For a POST request you pass the method, a header and a string body:
// scripts/add-post.js
const response = await fetch('http://localhost:3000/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'A post from a script', body: 'Sent with fetch' }),
});
const post = await response.json();
console.log(response.status, post.id);It prints 201 and the new post's number — the same result as curl in the previous lesson.
Limiting the wait
If an external server hangs, fetch() waits a very long time. AbortSignal.timeout() aborts the request after the given number of milliseconds:
// scripts/check-blog.js
try {
const response = await fetch('http://localhost:3000/posts', {
signal: AbortSignal.timeout(3000),
});
console.log(response.status);
} catch (error) {
console.log(`The server did not answer: ${error.name}`);
}If there is no answer for three seconds, "The server did not answer: TimeoutError" is printed. If the server is not running, the error also lands in catch — named TypeError with the message fetch failed.
What the response offers
| Property or method | What it gives |
|---|---|
response.status | The status code |
response.ok | true for codes 200–299 |
response.headers.get(name) | A header value |
await response.json() | The body parsed as JSON |
await response.text() | The body as a string |
Common mistake
In the browser you can write fetch('/posts') because the address is completed from the current page. Node.js has no page, and a relative address causes an error:
TypeError: Failed to parse URL from /postsAlways pass the full address with protocol and host: http://localhost:3000/posts. The base address is convenient to keep in an environment variable.