This document explains how to work with APIs in the application using React Query and Axios.
- API Client Setup
- Making API Requests
- React Query Integration
- Error Handling
- Authentication
- Mocking API Responses
The project uses fetch as the HTTP client. The base configuration is set up in src/services/api.ts:
import { api } from '../services/api';
export const fetchPosts = async (): Promise<Post[]> => {
const response = await api.get<Post[]>('/posts');
return response.data;
};export const createPost = async (postData: CreatePostDto): Promise<Post> => {
const response = await api.post<Post>('/posts', postData);
return response.data;
};// src/services/postService.ts
import { useQuery } from '@tanstack/react-query';
export const usePosts = () => {
return useQuery<Post[], Error>({
queryKey: ['posts'],
queryFn: fetchPosts,
staleTime: 5 * 60 * 1000, // 5 minutes
});
};// src/services/postService.ts
import { useMutation, useQueryClient } from '@tanstack/react-query';
export const useCreatePost = () => {
const queryClient = useQueryClient();
return useMutation<Post, Error, CreatePostDto>({
mutationFn: createPost,
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
};Global error handling is set up in the Axios response interceptor:
api.interceptors.response.use(
(response) => response,
(error) => {
const errorMessage = error.response?.data?.message || 'An error occurred';
// Show error toast
toast.error(errorMessage);
// Log error for debugging
console.error('API Error:', error);
return Promise.reject(error);
}
);const { data, error } = usePosts();
if (error) {
return <div>Error: {error.message}</div>;
}export const login = async (credentials: LoginDto): Promise<AuthResponse> => {
const response = await api.post<AuthResponse>('/auth/login', credentials);
return response.data;
};
// In a component
const loginMutation = useMutation({
mutationFn: login,
onSuccess: (data) => {
localStorage.setItem('auth_token', data.token);
// Update auth state
},
onError: (error) => {
toast.error(error.message);
},
});For development and testing, you can use the provided mock service worker:
- Create a mock handler in
src/mocks/handlers.ts:
import { rest } from 'msw';
export const handlers = [
rest.get('/api/posts', (req, res, ctx) => {
return res(
ctx.delay(150),
ctx.json([
{ id: 1, title: 'Post 1' },
{ id: 2, title: 'Post 2' },
])
);
}),
];- Start the mock server in development:
// src/main.tsx
if (import.meta.env.DEV) {
const { worker } = await import('./mocks/browser');
await worker.start();
}This setup allows you to develop and test your components without a backend server.