pramas, body, payload and headers in axios/fetch
| Term | What is it? | Where is it used? | When to use it? |
| Headers | Metadata about the request or response. Key-value pairs. | In all requests and responses. | Authentication (Authorization: Bearer <token>), Content Type (Content-Type: application/json), Caching (Cache-Control). |
Params (Query Parameters) | Non-sensitive data appended to the URL after a ?. | Primarily used for GET requests. | Filtering, sorting, and pagination (e.g., .../users?**status=active&page=1**). |
| Body / Payload | The actual data being sent to the server. | Primarily used for POST, PUT, and PATCH requests. | Creating or updating resources (e.g., sending user's name and email on a sign-up request). Note: These two terms are often used interchangeably to refer to the data sent in the request body. |
| URL Path | The main path of the resource. | In all requests. | Identifying the specific resource (e.g., /api/users/123). |
// lib/api-client-fetch.js
const BASE_URL = process.env.API_BASE_URL; // Use environment variables!
// Production-ready fetch wrapper
async function apiFetch(endpoint, options = {}) {
// 1. Headers: Merge custom headers with defaults (like Content-Type and Auth)
const defaultHeaders = {
'Content-Type': 'application/json',
// Best Practice: Get token from a secure, server-only source (e.g., cookies or Next.js headers() function)
'Authorization': options.token ? `Bearer ${options.token}` : undefined,
};
const finalOptions = {
...options,
headers: {
...defaultHeaders,
...options.headers, // Allow user to override or add new headers
},
// Next.js caching options for Server Components (e.g., force-cache, no-store, revalidate)
next: options.next || { revalidate: 3600 }
};
// 2. Body/Payload: Stringify the body for POST/PUT/PATCH requests
if (finalOptions.body && typeof finalOptions.body !== 'string') {
finalOptions.body = JSON.stringify(finalOptions.body);
}
const response = await fetch(`${BASE_URL}${endpoint}`, finalOptions);
if (!response.ok) {
// Production Grade Error Handling
const errorBody = await response.json().catch(() => ({ message: 'Unknown error' }));
throw new Error(`API Error: ${response.status} - ${errorBody.message}`);
}
// Handle successful response
return response.json();
}
// 3. Params (Query Parameters): Example use in a Server Component
// The component is the 'client' calling your API wrapper
export async function getPosts(filters) {
const searchParams = new URLSearchParams(filters).toString(); // { limit: 10, page: 1 } -> "limit=10&page=1"
const endpoint = `/posts?${searchParams}`;
return apiFetch(endpoint, {
method: 'GET',
// Example: Only revalidate every 60 seconds
next: { revalidate: 60 }
});
}
// 4. Payload (Body) and Headers: Example use for a POST request
export async function createPost(postData, userToken) {
// postData is the Payload/Body
return apiFetch('/posts', {
method: 'POST',
body: postData,
// Example: Passing a specific header (Authorization in this case)
token: userToken
});
}
// lib/api-client-axios.js
import axios from 'axios';
const api = axios.create({
baseURL: process.env.API_BASE_URL,
// 1. Headers: Default headers for ALL requests
headers: {
'Content-Type': 'application/json',
},
});
// Production Best Practice: Using Interceptors for global error/auth handling
api.interceptors.request.use((config) => {
// 1. Headers: Add Authorization header dynamically for every request
const token = localStorage.getItem('token'); // NOTE: Use for Client Components only!
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
api.interceptors.response.use(
(response) => response.data, // Axios automatically puts data in .data
(error) => {
// Production Grade Error Handling
if (error.response) {
console.error('Request failed:', error.response.data);
throw new Error(error.response.data.message || 'Server error');
} else {
console.error('Network Error:', error.message);
throw new Error('Network error or request timed out');
}
}
);
// 3. Params (Query Parameters): Example use
export async function getPosts(filters) {
// Axios uses the `params` key in the config object
return api.get('/posts', {
params: filters // filters: { limit: 10, page: 1 } -> /posts?limit=10&page=1
});
}
// 4. Payload (Body) and Headers: Example use for a POST request
export async function createPost(postData, userToken) {
// postData is the Payload/Body (first argument after the URL)
return api.post('/posts', postData, {
// Override or add a header for this specific request
headers: {
'Authorization': `Bearer ${userToken}`,
'X-Custom-Header': 'NextJS-App'
}
});
}
Comments