You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/blog/nodejs-http-request/index.md
+25-3Lines changed: 25 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,14 @@ Making HTTP requests is one of the most common tasks in Node.js development. Whe
23
23
24
24
The good news is that modern Node.js includes everything you need to make HTTP requests without installing any external packages. If you've done HTTP requests in the browser before, what you'll learn today will feel very familiar. In this guide, we'll explore the built-in options and when to use each one.
25
25
26
+
:::note[Prerequisites]
27
+
The examples in this guide use **top-level `await`**, which requires ESM (ECMAScript Modules). To use these examples, either:
28
+
- Set `"type": "module"` in your `package.json`, or
29
+
- Use the `.mjs` file extension
30
+
31
+
All examples assume Node.js 18 or later.
32
+
:::
33
+
26
34
## Quick Answer: Use `fetch()`
27
35
28
36
I get it, you don't have time to become an expert on everything there's to know about making HTTP requests with Node.js, so here's the quick answer you might be looking for.
@@ -179,7 +187,7 @@ try {
179
187
}
180
188
```
181
189
182
-
`AbortSignal.timeout()` is available since Node.js 17.3 (or 16.14 LTS).
190
+
`AbortSignal.timeout()` is available since Node.js 18 (or 17.3+).
183
191
184
192
### Handling Different Response Types
185
193
@@ -380,6 +388,10 @@ This `fetchWithRetry` helper wraps `fetch()` and automatically retries failed re
380
388
381
389
Note that this example is opinionated: it always parses the response as JSON and treats any non-OK status code as an error worth retrying. For a more flexible approach, you could return the raw response and let the caller decide how to parse it, or add logic to only retry on specific status codes (like 429 Too Many Requests or 503 Service Unavailable).
382
390
391
+
:::caution[Idempotency Warning]
392
+
This retry helper works best with **idempotent** GET requests. For POST/PUT/DELETE requests, retrying may cause duplicate side effects (like creating multiple orders). Additionally, if `options.body` is a stream, it can only be consumed once and retries will fail. For non-idempotent operations, either disable retries or implement request-specific retry logic.
393
+
:::
394
+
383
395
### Form Data and File Uploads
384
396
385
397
The earlier [Streaming Uploads](#streaming-uploads) section shows how to stream a file as raw bytes, where the entire request body is just the file content. That approach works when the API accepts a raw binary body, but most real-world APIs expect the `multipart/form-data` format instead. This format follows web standards (it's the same encoding used by HTML forms with `enctype="multipart/form-data"`) and lets you include metadata fields like descriptions, tags, or user IDs alongside the file.
@@ -543,18 +555,26 @@ Here's how to test it with mocked responses:
543
555
```javascript
544
556
// user-service.test.js
545
557
importassertfrom'node:assert/strict'
546
-
import { beforeEach, describe, it } from'node:test'
The `afterEach` cleanup is important: it closes the mock agent (releasing resources) and restores the original dispatcher. This prevents test pollution where mocks from one test leak into another, and avoids resource leaks if you're running many tests. The `disableNetConnect()` call adds an extra safety net by ensuring tests fail fast if they accidentally try to make real HTTP requests.
606
+
585
607
Let's break down what's happening in this test file. We import `describe`, `it`, and `beforeEach` from Node.js's built-in test runner (`node:test`), along with `assert` for assertions. In the `beforeEach` hook, we create a fresh `MockAgent` and register it as the global dispatcher using `setGlobalDispatcher()`. This tells undici (and therefore `fetch()`) to route all requests through our mock.
586
608
587
609
Each test then uses `mockAgent.get()` to target a specific origin, `.intercept()` to match a path and method, and `.reply()` to define the mocked response. When our `getUser()` function calls `fetch()`, it gets the mocked response instead of making a real network request.
0 commit comments