REST Integration
REST APIs model data as resources addressed by URLs.
React does not require REST, but REST is still one of the most common ways React apps communicate with backends.
Resources and Methods
REST endpoints usually use nouns for resources and HTTP methods for actions.
GET /api/products list products
GET /api/products/42 get one product
POST /api/products create product
PATCH /api/products/42 update product fields
DELETE /api/products/42 delete productThe URL identifies the resource. The method describes what to do.
Fetching a List
async function getProducts({ page, query }) {
const params = new URLSearchParams({
page: String(page),
q: query,
});
const response = await fetch(`/api/products?${params}`);
if (!response.ok) {
throw new Error("Could not load products");
}
return response.json();
}Use URLSearchParams instead of building query strings by hand.
Creating a Resource
async function createProduct(input) {
const response = await fetch("/api/products", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(input),
});
if (!response.ok) {
throw new Error("Could not create product");
}
return response.json();
}Always serialize the body explicitly when sending JSON.
Status Codes Matter
Common status codes:
200: success with response body201: created204: success with no body400: invalid request401: unauthenticated403: authenticated but not allowed404: not found409: conflict422: validation error429: rate limited500: server error
Do not treat all failures the same in the UI.
Validation errors can show field messages. A server outage may show a retry button. A 401 may redirect to login.
Pagination and Filtering
Large lists should not be fetched all at once.
GET /api/orders?page=2&limit=25&status=openThe response might include metadata.
{
"items": [],
"page": 2,
"totalPages": 8,
"totalItems": 183
}React UI should handle empty pages, loading the next page, and filters changing while requests are in flight.
Optimistic Updates
An optimistic update changes the UI before the server confirms success.
async function completeTodo(todoId) {
setTodos((todos) =>
todos.map((todo) =>
todo.id === todoId ? { ...todo, completed: true } : todo
)
);
try {
await api.completeTodo(todoId);
} catch (error) {
setTodos((todos) =>
todos.map((todo) =>
todo.id === todoId ? { ...todo, completed: false } : todo
)
);
}
}Optimistic UI feels fast, but rollback logic must be correct.
Idempotency Awareness
Network failures can leave the client unsure whether the server completed a request.
For payments, orders, and other critical mutations, backends often support idempotency keys.
POST /api/orders
Idempotency-Key: 70f7b9c2Retrying with the same key should not create duplicate orders.
Common Mistakes
- Using
GETfor mutations because it is convenient. - Ignoring
response.ok. - Calling
response.json()for a204 No Contentresponse. - Fetching unbounded lists.
- Retrying non-idempotent mutations without backend support.
- Treating
401and403as the same error.
What does 403 Forbidden usually mean?
Practical Challenge
Design REST endpoints for a todo app.
Include:
- list todos with filters
- create a todo
- edit a title
- mark complete
- delete a todo
- handle validation errors
Then write React request functions for each endpoint.
Recap
REST integration is about clear resource contracts, meaningful status handling, pagination, retries, and careful mutation behavior.
React components should not need to know every low-level HTTP detail, but they should receive enough information to show the right UI.