Spaces:
Sleeping
Sleeping
| # Fetch to Axios Migration Guide | |
| This document outlines the pattern for migrating fetch API calls to axios in our codebase. | |
| ## Why migrate from fetch to axios? | |
| Axios provides several advantages over the native fetch API: | |
| - Automatic JSON data transformation | |
| - Better error handling | |
| - Request/response interceptors | |
| - Simpler syntax for common operations | |
| - Consistent error objects | |
| ## Migration Pattern | |
| ### 1. Import axios | |
| First, add the axios import to your file: | |
| ```typescript | |
| import axios from 'axios'; | |
| ``` | |
| ### 2. Replace GET requests | |
| **Before (with fetch):** | |
| ```typescript | |
| const response = await fetch(url, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // other headers... | |
| }, | |
| mode: 'cors', | |
| credentials: 'include' // or 'omit' | |
| }); | |
| if (!response.ok) { | |
| const errorText = await response.text(); | |
| throw new Error(`Failed: ${response.status} ${response.statusText}`); | |
| } | |
| const data = await response.json(); | |
| return data; | |
| ``` | |
| **After (with axios):** | |
| ```typescript | |
| const response = await axios.get(url, { | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // other headers... | |
| }, | |
| withCredentials: true // replaces credentials: 'include' | |
| // Note: 'mode: cors' is not needed with axios | |
| }); | |
| // No need to check response.ok - axios throws on error status codes | |
| // No need to parse JSON - axios does this automatically | |
| return response.data; | |
| ``` | |
| ### 3. Replace POST requests | |
| **Before (with fetch):** | |
| ```typescript | |
| const response = await fetch(url, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // other headers... | |
| }, | |
| body: JSON.stringify(data), | |
| mode: 'cors', | |
| credentials: 'include' // or 'omit' | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`Failed: ${response.status} ${response.statusText}`); | |
| } | |
| const responseData = await response.json(); | |
| return responseData; | |
| ``` | |
| **After (with axios):** | |
| ```typescript | |
| const response = await axios.post(url, data, { | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // other headers... | |
| }, | |
| withCredentials: true // if needed | |
| }); | |
| return response.data; | |
| ``` | |
| ### 4. Replace PUT requests | |
| **Before (with fetch):** | |
| ```typescript | |
| const response = await fetch(url, { | |
| method: 'PUT', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // other headers... | |
| }, | |
| body: JSON.stringify(data), | |
| mode: 'cors', | |
| credentials: 'include' // or 'omit' | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`Failed: ${response.status} ${response.statusText}`); | |
| } | |
| const responseData = await response.json(); | |
| return responseData; | |
| ``` | |
| **After (with axios):** | |
| ```typescript | |
| const response = await axios.put(url, data, { | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // other headers... | |
| }, | |
| withCredentials: true // if needed | |
| }); | |
| return response.data; | |
| ``` | |
| ### 5. Replace DELETE requests | |
| **Before (with fetch):** | |
| ```typescript | |
| const response = await fetch(url, { | |
| method: 'DELETE', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // other headers... | |
| }, | |
| mode: 'cors', | |
| credentials: 'include' // or 'omit' | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`Failed: ${response.status} ${response.statusText}`); | |
| } | |
| // Handle response as needed | |
| ``` | |
| **After (with axios):** | |
| ```typescript | |
| const response = await axios.delete(url, { | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // other headers... | |
| }, | |
| withCredentials: true // if needed | |
| }); | |
| // response.data is already parsed if JSON was returned | |
| ``` | |
| ### 6. Error Handling | |
| **Before (with fetch):** | |
| ```typescript | |
| try { | |
| const response = await fetch(url); | |
| if (!response.ok) { | |
| const errorText = await response.text(); | |
| console.error(`API error: ${response.status} ${response.statusText}`, errorText); | |
| throw new Error(`Failed: ${response.status} ${response.statusText}`); | |
| } | |
| const data = await response.json(); | |
| return data; | |
| } catch (error) { | |
| console.error('Request failed:', error); | |
| throw error; | |
| } | |
| ``` | |
| **After (with axios):** | |
| ```typescript | |
| try { | |
| const response = await axios.get(url); | |
| return response.data; | |
| } catch (error) { | |
| if (axios.isAxiosError(error)) { | |
| console.error('API error:', error.message); | |
| console.error('Status:', error.response?.status); | |
| console.error('Data:', error.response?.data); | |
| throw new Error(`API Error: ${error.response?.status} ${error.message}`); | |
| } | |
| console.error('Request failed:', error); | |
| throw error; | |
| } | |
| ``` | |
| ## Common Patterns by File Type | |
| ### Service Files | |
| For service files, follow this general pattern: | |
| ```typescript | |
| import axios from 'axios'; | |
| import { API_BASE_URL } from '@/config'; | |
| export const exampleService = { | |
| getAll: async () => { | |
| try { | |
| const response = await axios.get(`${API_BASE_URL}/api/resource`, { | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| withCredentials: false | |
| }); | |
| return response.data; | |
| } catch (error) { | |
| console.error('Error:', error); | |
| return []; // or throw error depending on your error handling strategy | |
| } | |
| }, | |
| getById: async (id) => { | |
| try { | |
| const response = await axios.get(`${API_BASE_URL}/api/resource/${id}`); | |
| return response.data; | |
| } catch (error) { | |
| console.error(`Error fetching resource ${id}:`, error); | |
| throw error; | |
| } | |
| }, | |
| create: async (data) => { | |
| try { | |
| const response = await axios.post(`${API_BASE_URL}/api/resource`, data); | |
| return response.data; | |
| } catch (error) { | |
| console.error('Error creating resource:', error); | |
| throw error; | |
| } | |
| } | |
| // etc. | |
| }; | |
| ``` | |
| ### Component Files | |
| For component files, integrate axios calls as follows: | |
| ```typescript | |
| import axios from 'axios'; | |
| import { API_BASE_URL } from '@/config'; | |
| const YourComponent = () => { | |
| useEffect(() => { | |
| const fetchData = async () => { | |
| try { | |
| const response = await axios.get(`${API_BASE_URL}/api/resource`); | |
| setData(response.data); | |
| } catch (error) { | |
| console.error('Error fetching data:', error); | |
| setError('Failed to load data'); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| fetchData(); | |
| }, []); | |
| // rest of component | |
| }; | |
| ``` | |
| ## Remaining Files to Update | |
| Based on our analysis, these files need to be updated: | |
| - src/pages/project-detail.tsx | |
| - src/pages/project-edit.tsx | |
| - src/pages/projects.tsx | |
| - src/components/appraisal/AppraisalForm.tsx | |
| - src/pages/appraisal/assessment-areas.tsx | |
| - src/utils/create-indicators.js | |
| - src/pages/appraisal/competencies.tsx | |
| - src/pages/appraisal/cycles.tsx | |
| - src/pages/appraisal/hr-remarks.tsx | |
| - src/pages/appraisal/management-remarks.tsx | |
| - src/pages/appraisal/manager-dashboard.tsx | |
| Follow the patterns in this guide to update these files. |