Fetching API and CORS

Introduction

React apps load data from REST APIs with fetch. In development, Vite runs on port 5173 while FastAPI or Flask runs elsewhere—browsers enforce CORS. This chapter covers env URLs, Vite proxy, typed clients, loading/error UI, JWT headers, and custom hooks—parallel to Vue Fetching API.

Prerequisites

Environment Base URL

.env:

env
VITE_API_URL=

Empty with proxy—use relative /api/... paths.

src/api/client.ts:

Code explanation:

  • Only VITE_* vars are exposed to the browser
  • Never put server secrets in VITE_ variables

Vite Dev Proxy

vite.config.ts:

Frontend:

typescript
const posts = await apiGet<Post[]>("/api/v1/posts");

Browser sees same origin localhost:5173; Vite forwards to the API.

See Flask CORS and Frontend when not using a proxy.

CORS on the Backend

Cross-origin without proxy requires API CORS headers.

FastAPI — Middleware and CORS:

python
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173"],
    allow_methods=["*"],
    allow_headers=["*"],
)

Django: API auth and CORS.

Production: restrict origins to your real frontend domain.

Authenticated Fetch

usePosts Hook

src/hooks/usePosts.ts:

Three-State UI

axios (Optional)

bash
npm install axios
typescript
import axios from "axios";
 
const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
});
 
api.interceptors.request.use((config) => {
  const token = localStorage.getItem("token");
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

This track uses fetch by default—axios is a team preference.

BackendChapter
FastAPIREST CRUD project
DjangoBlog REST
FlaskCORS integration

Blog reader project: chapter 23 — same API as Vue 24.

FAQ

fetch in useEffect vs loader?

Both valid—useEffect + hook is flexible; router loader colocates data with route.

POST JSON?

typescript
await fetch("/api/v1/posts", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ title }),
});

Send CSRF token header—Bearer JWT in header avoids cookie CSRF for SPAs.

OpenAPI types?

Generate with openapi-typescript—optional advanced step.

Next chapter?

TypeScript With React.