Sitemap
DevManus

DevManus

Why you should stop harcoding api in React?

2 min readJan 4, 2026

At the beginning, hardcoding an API URL inside a component feels harmless.

You need data, you write fetch(“/api/users”), and you move on.

Fast forward a few months.

Get DevManus’s stories in your inbox

Join Medium for free to get updates from this writer.

Now the same URL exists in 20 or 50 different files. Some point to /api/users, some to /api/v1/users, some still hit the old staging domain. Nobody is fully sure which one is correct anymore.

// ❌ BAD: API URLs everywhere

function UserProfile({ userId }) {
useEffect(() => {
fetch(`https://api.myapp.com/v1/users/${userId}`)
.then(res => res.json())
.then(setUser);
}, [userId]);
}

function UserPosts({ userId }) {
useEffect(() => {
fetch(`https://api.myapp.com/v1/users/${userId}/posts`)
.then(res => res.json())
.then(setPosts);
}, [userId]);
}

function UpdateProfile({ userId }) {
const handleSubmit = async (data) => {
await fetch(`https://api.myapp.com/v1/users/${userId}`, {
method: 'PUT',
body: JSON.stringify(data),
});
};
}

Fix Part

// Usage is now clean and safe!

import { ENDPOINTS } from '@/config/api';

function UserProfile({ userId }) {
useEffect(() => {
fetch(ENDPOINTS.users.detail(userId))
.then(res => res.json())
.then(setUser);
}, [userId]);
}

function UserPosts({ userId }) {
useEffect(() => {
fetch(ENDPOINTS.users.posts(userId))
.then(res => res.json())
.then(setPosts);
}, [userId]);
}

// Switch environments? Change ONE file! ✨


// Endpoint builders
export const ENDPOINTS = {
// Users
users: {
list: () => `${API_BASE}/users`,
detail: (id) => `${API_BASE}/users/${id}`,
posts: (id) => `${API_BASE}/users/${id}/posts`,
followers: (id) => `${API_BASE}/users/${id}/followers`,
settings: (id) => `${API_BASE}/users/${id}/settings`,
},

// Products
products: {
list: () => `${API_BASE}/products`,
detail: (id) => `${API_BASE}/products/${id}`,
reviews: (id) => `${API_BASE}/products/${id}/reviews`,
related: (id) => `${API_BASE}/products/${id}/related`,
},

// Orders
orders: {
list: () => `${API_BASE}/orders`,
detail: (id) => `${API_BASE}/orders/${id}`,
create: () => `${API_BASE}/orders`,
cancel: (id) => `${API_BASE}/orders/${id}/cancel`,
},

// Auth
auth: {
login: () => `${API_BASE}/auth/login`,
logout: () => `${API_BASE}/auth/logout`,
register: () => `${API_BASE}/auth/register`,
refresh: () => `${API_BASE}/auth/refresh`,
forgotPassword: () => `${API_BASE}/auth/forgot-password`,
},
};


// ✅ Fix – Centralize API configuration:

// GOOD: Single source of truth
// config/api.js

const API_CONFIG = {
development: {
baseUrl: 'http://localhost:3001/api',
version: 'v1',
},

staging: {
baseUrl: 'https://staging-api.myapp.com',
version: 'v1',
},

production: {
baseUrl: 'https://api.myapp.com',
version: 'v1',
},
};

const env = process.env.NODE_ENV || 'development';
const config = API_CONFIG[env];

export const API_BASE = `${config.baseUrl}/${config.version}`;

--

--