Skip to main content

Making API calls

Every web app needs to communicate with a backend. JavaScript’s fetch() function handles HTTP requests - GET to retrieve data, POST to create data, PUT to update, DELETE to remove. You’ll use this pattern in almost every React component that needs backend data.

Basic GET request

fetch() returns a Promise, so you need await. The response needs to be converted to JSON with .json().
The .json() method also returns a Promise, which is why it needs await too. It reads the response body and parses it as JSON.

Handling errors

Always check response.ok before parsing. A 404 or 500 status won’t throw an error automatically - you have to check for it.
fetch() only throws on network errors (no internet, DNS failure, etc.), not on HTTP error status codes. A 404 or 500 response is considered a “successful” fetch. Always check response.ok.

POST request with data

POST requests need three things:
  1. method: 'POST' - tells the server you’re creating data
  2. headers with Content-Type: application/json - tells the server you’re sending JSON
  3. body with JSON.stringify() - converts your JavaScript object to a JSON string
Always use JSON.stringify() when sending data to an API. The body must be a string, not a JavaScript object.

PUT and DELETE requests

PUT and DELETE follow the same pattern. DELETE requests usually don’t have a body, and often return status 204 (No Content) instead of JSON.

Using environment variables

Store your API URL in a .env file so you can change it between development and production without modifying code.
In Vite (the build tool we’ll use), environment variables must start with VITE_ to be exposed to your code. In your .env file: VITE_API_URL=http://localhost:8000

Complete example with error handling

api/users.js
This is the pattern you’ll use in every project - a separate file with all your API functions, proper error handling, and environment variables.
Put all your API functions in a separate file (like api/users.js). This separates concerns and makes your code easier to test and maintain.

Common mistakes

Without await, you get a Promise object, not the data. This is one of the most common async mistakes. Remember: fetch() returns a Promise, and so does .json().
A 404 or 500 response won’t throw an error automatically. Always check response.ok before calling .json(). Otherwise you might try to parse an error page as JSON and get confusing errors.
The body must be a string, not a JavaScript object. Always use JSON.stringify(), and don’t forget the Content-Type header.
Network requests can fail for many reasons - no internet, server down, CORS errors. Always wrap fetch calls in try/catch so you can handle errors gracefully.

What’s next?

You can now fetch data from your FastAPI backend. Next, let’s learn how to work with the responses you get back — status codes, headers, and different response formats.

Handling responses

Parse API responses and work with different formats