Skip to content
Back to Knowledge Hub

JavaScript practice

How should a frontend handle loading, errors and empty API results?

Treat loading, success with data, success without data and failure as distinct UI states. A completed fetch is not proof of HTTP success: check response.ok before reading the result.

By Alhaji C. M. Kallon · · intermediate · 4 min with practice

Before you start

  • Write async JavaScript functions
  • Understand JSON

What you will practise

  • Distinguish HTTP errors from network errors
  • Plan loading and empty states

Quick answer

Treat loading, success with data, success without data and failure as distinct UI states. A completed fetch is not proof of HTTP success: check response.ok before reading the result.

Build a small example

async function loadProjects(signal) {
  const response = await fetch('/api/projects', { signal });
  if (!response.ok) throw new Error('Projects are unavailable');
  const data = await response.json();
  if (!Array.isArray(data)) throw new Error('Unexpected response');
  return data;
}

The example endpoint is illustrative; your application must provide it. Validate each record before displaying fields, not just the outer array.

Try it yourself

Create fixtures for a non-empty array, an empty array, an HTTP error and malformed JSON. Write the visitor-facing message for each. Test a slow connection and two quickly superseded requests.

Common mistake

A stale response can overwrite newer results. Abort superseded work and guard state updates so cancelled requests cannot replace the current view. Treat deliberate cancellation separately from a service failure.

Check your understanding

Should an empty successful response show “something went wrong”? No. Explain that no items match and provide a useful next action.

Next step

Read runtime validation with TypeScript.

Sources and further reading

Published 2 November 2026. Examples are teaching exercises, not claims about client results.