DEV Community

Cover image for How to Fetch Data from an API in JavaScript (fetch Explained Simply)
Lavkush kumar
Lavkush kumar

Posted on Originally published at codingcush.com

How to Fetch Data from an API in JavaScript (fetch Explained Simply)

Originally published on CodingCush.

To fetch data from an API in JavaScript, use the built-in fetch() function: call fetch(url), wait for the response, then call response.json() to turn the reply into data your code can use. That is the whole idea. No library, no extra download, and no mysterious setup — fetch is already waiting in every modern browser, ready to ask a server for data and bring it back to your page.

What Fetch Actually Does

Think of fetch as a polite messenger. Your page needs something — a list of products, the weather, a user's profile — and that something lives on a server somewhere else. You hand the messenger an address, he goes and asks nicely, and he comes back with a parcel. Your job is simply to open the parcel.

If the word API still feels fuzzy, start with our simple guide on what an API is, explained simply, then come back here. In short, an API is the menu and the waiter combined: it tells you what you can request, and it delivers exactly that when you ask correctly.

One important detail catches almost every beginner: fetch() does not hand you the data straight away. It returns a Promise, which is JavaScript's way of saying, "I am working on it, check back in a moment." The network takes time, and JavaScript refuses to freeze your whole page while it waits. Sensible, really — nobody likes a website that stares blankly at them.

The full reference lives in the MDN overview of the Fetch API, which lists every part of the standard in one place. Keep it bookmarked; you will visit it more often than your favourite social feed, at least on productive days.

Your First Fetch with .then()

The classic way to use fetch is with .then(), which runs a function when the Promise finishes. Here is a complete GET request that loads a list of posts from a practice API and prints the first title:

fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {
    console.log("Title:", data.title);
    console.log("Body:", data.body);
  })
  .catch(function (error) {
    console.log("Something went wrong:", error);
  });
Enter fullscreen mode Exit fullscreen mode

Read it top to bottom and it almost tells its own story. First, fetch sends a GET request to the URL. Next, the first .then() receives the raw response and converts it with response.json(). Then the second .then() receives the actual data, ready to display. Finally, .catch() handles anything that failed along the way, such as having no internet connection.

Notice there are two steps, not one. The response arrives first as a parcel, and .json() unwraps it. Forgetting that second step is the number one reason beginners stare at a Promise in the console and wonder where their data went. It is in there — you just have not opened the box yet.

The Same Fetch with async and await

Most modern code uses async and await instead, because it reads like a simple list of instructions. The work underneath is identical; only the writing style changes. If Promises still feel slippery, our tutorial on JavaScript Promises and async/await explained walks through them slowly with examples.

async function loadPost() {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    const data = await response.json();
    console.log("Title:", data.title);
    console.log("Body:", data.body);
  } catch (error) {
    console.log("Something went wrong:", error);
  }
}

loadPost();
Enter fullscreen mode Exit fullscreen mode

Each await simply means "pause this function here until the Promise finishes, then carry on". The rest of your page keeps running happily; only this function waits. For most new projects, this is the style worth learning first, because longer code stays far easier to read and debug.

MDN documentation page introducing web APIs in JavaScript

MDN’s introduction to web APIs — fetch is the built-in API this guide uses to request data.

Reading the Response Properly

A response is more than just data. It carries a status code and a handy ok flag that tells you whether the server was happy with your request. Status 200 means success, 404 means the address was not found, and 500 means the server itself had a bad day — it happens to the best of us.

async function loadUser(id) {
  const response = await fetch("https://jsonplaceholder.typicode.com/users/" + id);

  if (!response.ok) {
    console.log("Server replied with status:", response.status);
    return;
  }

  const user = await response.json();
  console.log("Name:", user.name);
  console.log("Email:", user.email);
}

loadUser(1);
Enter fullscreen mode Exit fullscreen mode

Here is the surprise that catches people out: fetch does not treat a 404 or 500 as an error. As far as fetch is concerned, the messenger came back, so the job succeeded — even if the parcel contains bad news. That is why checking response.ok yourself is a habit worth building from day one. Depending on the reply, you can also use response.text() for plain text or response.blob() for files and images.

Sending Data with a POST Request

So far we have only asked for data. To send data — a form, a new comment, a signup — pass fetch a second argument: an options object that sets the method, the headers, and the body.

async function createPost() {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        title: "Learning fetch",
        body: "fetch makes sending data surprisingly calm.",
        userId: 1
      })
    });

    const result = await response.json();
    console.log("Server saved it with id:", result.id);
  } catch (error) {
    console.log("Could not save:", error);
  }
}

createPost();
Enter fullscreen mode Exit fullscreen mode

Three pieces matter here. The method says what you want to do: POST creates something new, while PUT updates and DELETE removes. The Content-Type header tells the server, "this parcel contains JSON, please open it that way." And JSON.stringify() turns your JavaScript object into a JSON string, because the network carries text, not live objects.

The step-by-step MDN guide to using the Fetch API shows these same options with more variations, including file uploads. When you are unsure about an option's exact name, that page is the safest place to check before guessing.

Fetch Compared with the Old Way

Before fetch, developers used XMLHttpRequest, a powerful but clunky tool from an earlier era of the web. It still works, and old code still uses it, but for new code the difference is clear:

Feature fetch XMLHttpRequest
Built into browsers Yes, modern standard Yes, older standard
Code style Promises, works with async/await Callbacks and event listeners
Reading JSON One step: response.json() Manual parsing with JSON.parse()
Typical length Short and readable Longer and more repetitive
Best for Almost all new code Maintaining older projects

Neither tool is magic; both simply talk to a server. The win with fetch is that your code stays short enough to understand at a glance, which matters at midnight when something breaks and the only person available to fix it is a slightly tired you.

Common Mistakes to Avoid

A few small traps appear again and again. First, forgetting await before response.json(), which leaves you holding a Promise instead of data. Second, assuming a 404 will land in .catch() — it will not, so always check response.ok. Third, sending an object as the body without JSON.stringify(), which posts the deeply unhelpful text "[object Object]" to the server. Fourth, forgetting the Content-Type header, so the server receives JSON but treats it as plain text and ignores it.

Finally, remember that fetch runs in the browser, so the API must allow your site to call it. If the console shows a CORS error, that is the server refusing browser requests from your domain — annoying, but it is a server setting to fix, not a bug in your fetch code.

Frequently Asked Questions

Is fetch available in all browsers?

Yes, every modern browser supports fetch, including Chrome, Firefox, Safari and Edge. It also works in Node.js from version 18 onwards, so the same code style now runs on the server too.

What is the difference between .then() and async/await?

They do exactly the same job with Promises. .then() chains functions together, while async/await makes the same waiting look like ordinary step-by-step code. Most developers find async/await easier to read in longer functions.

Why does fetch not fail on a 404 error?

Because fetch only fails when the request itself cannot complete, for example with no network connection. A 404 still counts as a completed reply from the server, so check response.ok or response.status yourself.

Can fetch send headers, such as an API key?

Yes. Add a headers object to the options, just like the Content-Type example above. Many APIs accept a key this way, for example with an Authorization header. Keep private keys off public front-end code whenever you can, though.

Conclusion

You now know the complete fetch pattern: call the URL, check response.ok, unwrap the data with response.json(), and handle failures with .catch() or try/catch. Practise with a free practice API, try one GET and one POST, and within an hour this will feel like the most natural thing in JavaScript — because, data-wise, it is.

Top comments (0)