Handling JSON API Responses in JavaScript

Learn how to handle JSON API responses in JavaScript using fetch and .json(). Practical examples of GET, POST, error handling, and parsing response data.

4 min read

When JavaScript talks to a server, the most common data format is JSON. The browser's fetch function sends the request, and the response object's .json() method reads the body and parses the JSON into a JavaScript object in one step.

javascriptjavascript
async function getUser(id) {
  const response = await fetch(`https://api.example.com/users/${id}`);
  const user = await response.json();
  console.log(user.name);
}

The first await waits for the server to respond. The second await reads the response body and parses it as JSON. After both, user is a plain JavaScript object ready to use.

For the fundamentals of converting between JSON strings and objects, see the guide to JSON parse and stringify.

Fetching JSON with GET

A GET request is the most common operation. The pattern has three steps: fetch the URL, check the status, then parse the JSON.

javascriptjavascript
async function fetchPosts() {
  const response = await fetch("https://jsonplaceholder.typicode.com/posts");
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return response.json();
}

response.ok is true for status codes 200 through 299 and false for errors like 404 or 500. fetch does not throw on error statuses, so checking ok yourself is mandatory. Once you confirm the response is valid, a single call to .json() gives you the parsed data.

The parsed data is a normal JavaScript value. If the API returns an array, you get an array with all the standard methods available. If it returns an object, you can access properties directly.

Sending JSON with POST

To send data to a server, change the method to POST, add the Content-Type header, and stringify your data as the body.

javascriptjavascript
async function createUser(name, email) {
  const response = await fetch("https://api.example.com/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name, email })
  });
  if (!response.ok) throw new Error(`Failed: ${response.status}`);
  return response.json();
}

The Content-Type header tells the server to expect JSON in the request body. The body is the result of JSON.stringify, which converts the JavaScript object into a JSON string. The server typically returns the created resource, which you parse with .json() on the response.

Handling both network and HTTP errors

There are two kinds of errors with APIs. Network errors happen when the request cannot reach the server at all. HTTP errors happen when the server responds but with a failure status code.

javascriptjavascript
async function safeFetch(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.json();
  } catch (error) {
    console.error("Fetch failed:", error.message);
    return null;
  }
}

The outer try-catch catches network errors like DNS failures or CORS blocks. The inner ok check catches HTTP errors like 404 or 500. The function returns null on any failure instead of crashing, which lets the caller handle the absence of data gracefully.

Checking response content type

Some APIs return HTML error pages instead of JSON when something goes wrong. Checking the Content-Type header before calling .json() prevents unexpected parse errors.

javascriptjavascript
async function parseIfJson(response) {
  const contentType = response.headers.get("content-type");
  if (contentType && contentType.includes("application/json")) {
    return await response.json();
  }
  console.error("Unexpected response format");
  return null;
}

This defensive pattern is useful when consuming third-party APIs where you cannot control the error response format. For date formatting within the parsed data, see the guide to formatting dates.

Common mistakes

Forgetting to call .json() on the response and trying to use the response object directly is the most frequent error. The response object is not the data. You must await response.json() to get the parsed body.

Not checking response.ok before parsing assumes the request succeeded. Calling .json() on a 404 response that contains an HTML error page throws a parsing error with a confusing message.

Using .json() twice on the same response throws because the body stream can only be read once. If you need to both log and parse the response, call response.clone().json() for the second read.

Forgetting the Content-Type header on POST requests means the server may not parse your JSON body correctly. Always include "Content-Type": "application/json" when sending JSON data.

Rune AI

Rune AI

Key Insights

  • Use fetch(url) for GET and response.json() to parse the JSON body.
  • fetch does not throw on 404 or 500. Check response.ok before parsing.
  • For POST, set method, headers, and JSON.stringify the body.
  • Wrap fetch in try-catch for network errors. Handle HTTP errors separately.
  • Use async/await for readable code when processing API responses.
RunePowered by Rune AI

Frequently Asked Questions

Do I need to call JSON.parse on a fetch response?

No. Use the .json() method on the response object: const data = await response.json(). This reads the body stream and parses it as JSON in one step.

What happens if the API returns a 404 error?

fetch does not throw on HTTP error statuses. You must check response.ok or response.status manually. If the status is not ok, handle it before calling .json().

How do I send JSON in a POST request body?

Use JSON.stringify on your data and set the Content-Type header: fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }).

Conclusion

Handling JSON API responses follows a consistent pattern: call fetch, check if the response is OK, then call response.json() to parse the body. For POST requests, stringify your data and set the Content-Type header. Always handle error statuses explicitly because fetch does not throw on them.