Enhanced error handling and debugging to diagnose API connection problems. Changes: - Added detailed console logging in API client (client.ts) - Enhanced error display in projects page with troubleshooting steps - Added logging in useProjects hook for better debugging - Display API URL and error details on error screen - Added retry button for easy error recovery This will help diagnose why the backend API (localhost:5167) is not connecting. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
125 lines
2.9 KiB
TypeScript
125 lines
2.9 KiB
TypeScript
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5000/api/v1';
|
|
|
|
// Log API URL for debugging
|
|
if (typeof window !== 'undefined') {
|
|
console.log('[API Client] API_URL:', API_URL);
|
|
console.log('[API Client] NEXT_PUBLIC_API_URL:', process.env.NEXT_PUBLIC_API_URL);
|
|
}
|
|
|
|
export class ApiError extends Error {
|
|
constructor(
|
|
public status: number,
|
|
message: string,
|
|
public data?: any
|
|
) {
|
|
super(message);
|
|
this.name = 'ApiError';
|
|
}
|
|
}
|
|
|
|
async function handleResponse<T>(response: Response): Promise<T> {
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
const error = new ApiError(
|
|
response.status,
|
|
errorData.message || response.statusText,
|
|
errorData
|
|
);
|
|
console.error('[API Client] Request failed:', {
|
|
url: response.url,
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
errorData,
|
|
});
|
|
throw error;
|
|
}
|
|
|
|
if (response.status === 204) {
|
|
return {} as T;
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
export async function apiRequest<T>(
|
|
endpoint: string,
|
|
options: RequestInit = {}
|
|
): Promise<T> {
|
|
const url = `${API_URL}${endpoint}`;
|
|
|
|
console.log('[API Client] Request:', {
|
|
method: options.method || 'GET',
|
|
url,
|
|
endpoint,
|
|
});
|
|
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
// Add auth token if available
|
|
if (typeof window !== 'undefined') {
|
|
const token = localStorage.getItem('accessToken');
|
|
if (token) {
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
}
|
|
|
|
// Merge with options headers
|
|
if (options.headers) {
|
|
Object.assign(headers, options.headers);
|
|
}
|
|
|
|
const config: RequestInit = {
|
|
...options,
|
|
headers,
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(url, config);
|
|
const result = await handleResponse<T>(response);
|
|
console.log('[API Client] Response:', {
|
|
url,
|
|
status: response.status,
|
|
data: result,
|
|
});
|
|
return result;
|
|
} catch (error) {
|
|
console.error('[API Client] Network error:', {
|
|
url,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
errorObject: error,
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export const api = {
|
|
get: <T>(endpoint: string, options?: RequestInit) =>
|
|
apiRequest<T>(endpoint, { ...options, method: 'GET' }),
|
|
|
|
post: <T>(endpoint: string, data?: any, options?: RequestInit) =>
|
|
apiRequest<T>(endpoint, {
|
|
...options,
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
}),
|
|
|
|
put: <T>(endpoint: string, data?: any, options?: RequestInit) =>
|
|
apiRequest<T>(endpoint, {
|
|
...options,
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
}),
|
|
|
|
patch: <T>(endpoint: string, data?: any, options?: RequestInit) =>
|
|
apiRequest<T>(endpoint, {
|
|
...options,
|
|
method: 'PATCH',
|
|
body: JSON.stringify(data),
|
|
}),
|
|
|
|
delete: <T>(endpoint: string, options?: RequestInit) =>
|
|
apiRequest<T>(endpoint, { ...options, method: 'DELETE' }),
|
|
};
|