API & webhooks
Node.js REST API GET: Build the URL and Check the Response
Call a JSON REST endpoint with Node fetch, encode query values, check HTTP status and response shape, and keep timeouts distinct from HTTP errors.
Use the runtime's HTTP client deliberately
In a current Node.js runtime with built-in fetch, a small REST API GET does not require installing a separate request library. The important work is constructing the intended URL, checking the HTTP result and validating the response shape before the rest of your program uses it. A fulfilled fetch promise alone does not mean the API returned a successful status.
The Node.js fetch guide describes the built-in client and its relationship to Undici. Check the Node version actually used by the deployed application, not only the version in your terminal. This example uses fetch, URL and AbortSignal.timeout as runtime APIs.
Request a filtered collection with explicit boundaries
async function listNotes(origin, tag, fetcher = fetch) {
const url = new URL("/notes", origin);
url.searchParams.set("tag", tag);
const response = await fetcher(url, {
headers: {Accept: "application/json"},
signal: AbortSignal.timeout(10000)
});
if (!response.ok) {
await response.body?.cancel();
throw new Error(`Notes request failed: HTTP ${response.status}`);
}
const data = await response.json();
if (!data || !Array.isArray(data.items)) {
throw new Error("The notes response must contain an items array.");
}
return data.items;
}
The function expects an origin such as https://api.example.com and an endpoint at /notes. The leading slash deliberately selects the origin's root path. If your API lives under /v2/, change the endpoint policy explicitly; passing a base URL with that prefix will not make this particular function retain it.
Using searchParams keeps a tag such as maps & walks in one query value. Concatenating an unescaped ampersand would create a second query component. Do not pre-encode the tag before passing it to searchParams, because doing both can encode the percent signs again.
Separate HTTP, JSON and application-shape errors
A readable 404 or 500 takes the explicit non-success branch. The example cancels the unused response body and reports the status. It intentionally does not publish the server's full error body. If your diagnostic workflow needs that body, read it with an appropriate size limit and redact sensitive fields before logging it.
A successful response containing invalid JSON fails while parsing. Valid JSON with a missing items array fails the next check. These are different defects, even though both prevent returning the requested collection. An empty items array is valid and should not be confused with a missing response.
The shape check is deliberately narrow. It verifies the collection container, not every note's fields. Add a schema or field checks when the caller depends on identifiers, dates or other properties. Avoid silently accepting a different response structure just because an API change still produces syntactically valid JSON.
Give the operation a bounded lifetime
The timeout signal can abort a slow request rather than leaving the caller waiting indefinitely. Treat that rejection separately from a readable HTTP error. A timeout means the client stopped waiting; it does not establish which response the server would eventually have produced.
Do not wrap every failure in an automatic retry loop. A small read may support a bounded retry under the provider's rules, but authentication failures and a malformed endpoint need correction. If several requests are launched together, bound concurrency and avoid multiplying retries across nested layers.
Test URL construction as well as returned data
Inject a controlled fetcher to verify that the outgoing URL contains exactly one tag value, including spaces, ampersands and Unicode. Test a nonempty collection, an empty collection, a 404, invalid JSON and an object with the wrong shape. A test that checks only the happy-path array misses the most common integration mistakes.
Also run the function against a local HTTP fixture so the real Node client and JSON parser are exercised. A fake function does not reproduce every connection behavior. Record the runtime version with that test, and keep external service availability out of a deterministic unit test.
The browser-based REST API Testing Tool can inspect a permitted endpoint's visible status and body, but its CORS environment differs from Node. A browser failure is not proof that the server-side Node request will fail, and moving a request to a backend requires its own access and destination controls.


