Send and Receive JSON

Send and Receive JSON

GET reads a representation; POST submits a request body. This deterministic Response example parses returned JSON. The additional request section shows actual fetch syntax and distinguishes HTTP failure from network rejection.

Before this topic, review Build an Accessible Toggle if its terms are unfamiliar.

What you’ll learn

  • Explain send and receive json through the school example.
  • Trace the shown operations and distinguish their result from displayed output.
  • Make the practice change and explain its consequence: The response body is changed, independently of its successful HTTP status.

Work through the school example

This is JavaScript in a browser. Read the initial values, then follow each operation to its displayed result. A declaration names a value, a function call performs an operation, and console.log displays its arguments.

JavaScript · browser · complete script for the supplied markup

async function report() {
  const response = new Response('{"saved":true}', { status: 201 });
  if (!response.ok) throw new Error("Save failed");
  console.log((await response.json()).saved);
}
report();

Expected output

true

Introduction to Fetch API

The fetch() API in JavaScript is a modern, promise-based way to make HTTP requests to servers. It works in all modern browsers and replaces the older XMLHttpRequest API with a cleaner and more powerful interface.

Why Use Fetch?

  • It returns Promises — making asynchronous programming more elegant
  • Supports JSON and other content types out-of-the-box
  • Allows better control over requests and responses

Example 1: GET Request Using Fetch

Let's fetch a list of users from a public API.

// Fetching users from JSONPlaceholder API
fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json(); // parse JSON body
  })
  .then(data => {
    console.log('Fetched users:', data);
  })
  .catch(error => {
    console.error('Fetch error:', error);
  });
Fetched users: [ { id: 1, name: 'Leanne Graham', ... }, ... ]

Question:

What does response.ok check for?

Answer: It checks whether the HTTP status is in the range 200–299. If not, the request is considered unsuccessful.

Example 2: POST Request Using Fetch

Now let's send data to the server using a POST request.

// Posting data to JSONPlaceholder API
const postData = {
  title: 'Hello Fetch',
  body: 'This is a POST request example.',
  userId: 1
};

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(postData)
})
  .then(response => response.json())
  .then(data => {
    console.log('POST success:', data);
  })
  .catch(error => {
    console.error('POST error:', error);
  });
POST success: { id: 101, title: 'Hello Fetch', body: 'This is a POST request example.', userId: 1 }

Question:

Why do we use JSON.stringify(postData)?

Answer: The body of a fetch POST request must be a string, so we convert the JavaScript object into a JSON string format before sending.

Handling Fetch Errors

Fetch only throws an error on network failure (like no internet). It won’t reject on HTTP errors like 404 or 500 — so you need to check response.ok manually.

fetch('https://jsonplaceholder.typicode.com/unknown-endpoint')
  .then(response => {
    if (!response.ok) {
      throw new Error(`Error: ${response.status}`);
    }
    return response.json();
  })
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error('Handled error:', error.message);
  });
Handled error: Error: 404

Points to Remember

  • fetch() always returns a Promise.
  • Always handle errors using .catch() or try/catch with async/await.
  • Use response.json() to parse the JSON response.
  • POST requests require setting the 'Content-Type' to 'application/json'.

Practice Tip

Try using fetch to make GET and POST requests to your own mock API using reqres.in or JSONPlaceholder.

Recognize the important boundary

Sending JSON requires the expected content type and server contract. POST is not automatically idempotent, and retries can duplicate operations.

Try a small variation

JavaScript · original source for practice

async function report() {
  const response = new Response('{"saved":true}', { status: 201 });
  if (!response.ok) throw new Error("Save failed");
  console.log((await response.json()).saved);
}
report();

Your task: Replace "saved":true with "saved":false. Predict the result before running the edited program.

The source is repeated here. If the edit targets the HTML rather than the script, use the markup repeated below; the worked answer also repeats the changed markup.

Worked answer and reasoning

The response body is changed, independently of its successful HTTP status.

JavaScript · complete worked variation

async function report() {
  const response = new Response('{"saved":false}', { status: 201 });
  if (!response.ok) throw new Error("Save failed");
  console.log((await response.json()).saved);
}
report();

Expected output

false

Predict the original program

JavaScript · original program for this question

async function report() {
  const response = new Response('{"saved":true}', { status: 201 });
  if (!response.ok) throw new Error("Save failed");
  console.log((await response.json()).saved);
}
report();
In the browser, what does the original JavaScript example display, in order?
Choose one answer. You can try again.

Answer and explanation

true

GET reads a representation; POST submits a request body. This deterministic Response example parses returned JSON. The additional request section shows actual fetch syntax and distinguishes HTTP failure from network rejection. Sending JSON requires the expected content type and server contract. POST is not automatically idempotent, and retries can duplicate operations.

Connect the response to a real request

This example makes a real same-origin HTTP request. Provide /__javascript-api/student on your own practice server with JSON such as {"marks":72}. This teaching endpoint is used by the verification server; it is not a public API on the deployed course. A successful response prints 72; HTTP and invalid-data failures enter catch.

For a POST, use fetch(endpoint, {method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({marks:72})}). The endpoint must implement that contract. Do not retry writes without understanding duplicate processing.

JavaScript · browser · real HTTP request with a practice endpoint

async function loadReport() {
  try {
    const response = await fetch('/__javascript-api/student');
    if (!response.ok) throw new Error('HTTP ' + response.status);
    const student = await response.json();
    if (!Number.isFinite(student.marks)) throw new Error('Invalid mark');
    console.log(student.marks);
  } catch (error) { console.log(error.message); }
}
loadReport();

Expected output

72

Keep the useful idea

GET reads a representation; POST submits a request body. This deterministic Response example parses returned JSON. The additional request section shows actual fetch syntax and distinguishes HTTP failure from network rejection.

Check your variation against this explanation: The response body is changed, independently of its successful HTTP status.

Use the JavaScript array reference library for individual array operations and boundary tests to check a rule independently.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Keep Interaction Responsive →