Check HTTP status before reading the expected data
fetch returns a promise for a Response. It normally rejects for network-level failures, not merely because the server responds with 404 or 500. Validate status, expected content and payload shape before updating the UI.
async function getCourses(signal) {
const response = await fetch('/api/courses', {
signal,
headers: { Accept: 'application/json' }
});
if (!response.ok) throw new Error('HTTP ' + response.status);
const data = await response.json();
if (!Array.isArray(data.courses)) throw new Error('Invalid course response');
return data.courses;
}This example assumes your own server implements /api/courses with a JSON object containing courses. It is an API contract example, not a claim that every website has that endpoint.
POST JSON
async function createNote(text) {
const response = await fetch('/api/notes', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify({ text })
});
if (!response.ok) throw new Error('Note was not saved');
return response.status === 204 ? null : response.json();
}Do not call response.json on an empty 204 body. The server must authenticate, authorize and validate the write. A user ID or role from the browser is not proof of permission. Follow the application's CSRF/session design for credentialed writes.
Cancellation and CORS
Create an AbortController, pass its signal and call abort when a request is superseded or no longer needed. An abort does not guarantee a server-side write never happened. Cross-origin browser access requires the server's CORS policy; no-cors does not provide a readable JSON response as a workaround.
Request lifecycle
Show loading before the request, an explicit empty state for an empty valid result, a useful retry action for failure and the actual data on success. Prevent an older response from replacing newer search results. Avoid blind retries of state-changing requests unless the operation has a deliberate idempotency strategy.
Practice
- Test success, 404, malformed JSON and a valid empty list on a local API.
- Cancel a slow read and distinguish cancellation from a server error.
- Return 204 from a test write and verify the client does not parse an absent body.
- Explain why fetch resolving is not sufficient proof of application success.