besper-frontend-site-dev-main
Version:
Professional B-esper Frontend Site - Site-wide integration toolkit for full website bot deployment
258 lines (226 loc) • 7.54 kB
JavaScript
/**
* Centralized API Service for B-esper Frontend Toolkit
* Consolidates all API endpoint definitions and provides consistent API calling interface
* Uses dynamic endpoints from build-time environment variables for APIM deployment flexibility
*/
// Dynamic base URL from build-time environment (NO FALLBACKS ALLOWED)
const APIM_BASE_ENDPOINT = process.env.API_ENDPOINT;
// Validate API_ENDPOINT is set during build - fail fast if not configured
if (!APIM_BASE_ENDPOINT) {
console.error(
'[ERROR] CRITICAL: API_ENDPOINT environment variable is required but not set!'
);
console.error('[ERROR] This indicates a build configuration error.');
console.error(
'[ERROR] Production deployments must set API_ENDPOINT to match infrastructure: {env}0926apim_internal.azure-api.net'
);
console.error(
'[ERROR] Build will fail - no hardcoded fallback endpoints allowed'
);
throw new Error(
'API_ENDPOINT environment variable is required for deployment - no fallbacks allowed'
);
}
/**
* Get the base APIM endpoint (dynamic only, no fallbacks)
*/
function getBaseAPIEndpoint() {
// Return only the dynamic endpoint - no fallback logic allowed
return APIM_BASE_ENDPOINT;
}
// API service paths
const API_PATHS = {
// Bot operations (chat, messaging)
botOperations: '/api/bot-operations',
// Bot management (configuration, settings)
botManagement: '/api/bot-management',
// Root API for general operations
root: '/api',
// Management operations (legacy mgmt path if needed)
management: '/mgmt',
};
/**
* Get the complete API endpoint URL for a specific service
* Uses ONLY the dynamic base endpoint from build-time environment variables
* NO FALLBACKS ALLOWED - ensures consistent infrastructure naming
* @param {string} service - Service name from API_PATHS
* @returns {string} Complete API endpoint URL
*/
export function getServiceEndpoint(service = 'botOperations') {
// Use ONLY the dynamic base endpoint - no fallbacks allowed
const baseUrl = getBaseAPIEndpoint();
const path = API_PATHS[service] || API_PATHS.botOperations;
// Ensure no double slashes
const endpoint = `${baseUrl}${path}`
.replace(/\/+/g, '/')
.replace('http:/', 'http://')
.replace('https:/', 'https://');
// Only log in development/debug mode to reduce console noise
if (
typeof window !== 'undefined' &&
window.location?.hostname?.includes('localhost')
) {
console.log(`[API] API Endpoint for ${service}:`, endpoint);
}
return endpoint;
}
/**
* Get bot operations endpoint (for chat functionality)
* Uses dynamic endpoint from build-time configuration
* @returns {string} Bot operations API endpoint
*/
export function getBotOperationsEndpoint() {
return getServiceEndpoint('botOperations');
}
/**
* Get bot management endpoint (for configuration management)
* Uses dynamic endpoint from build-time configuration
* @returns {string} Bot management API endpoint
*/
export function getBotManagementEndpoint() {
return getServiceEndpoint('botManagement');
}
/**
* Get root API endpoint (for general operations)
* Uses dynamic endpoint from build-time configuration
* @returns {string} Root API endpoint
*/
export function getRootApiEndpoint() {
return getServiceEndpoint('root');
}
/**
* Generic API call helper with enhanced error handling and logging
* @param {string} endpoint - Full API endpoint URL
* @param {string} method - HTTP method (GET, POST, PUT, DELETE)
* @param {Object} body - Request body for POST/PUT requests
* @param {Object} headers - Additional headers
* @returns {Promise<Object>} API response data
*/
export async function apiCall(
endpoint,
method = 'GET',
body = null,
headers = {}
) {
const config = {
method,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
...headers,
},
};
if (body && method !== 'GET') {
config.body = JSON.stringify(body);
}
// Debug logging (reduced in production)
const isDebugMode =
typeof window !== 'undefined' &&
(window.location?.hostname?.includes('localhost') ||
window.location?.search?.includes('debug=true'));
if (isDebugMode) {
console.log(`[API] Making ${method} request to:`, endpoint);
if (body) {
console.log(`📦 Request payload:`, body);
}
}
try {
const response = await fetch(endpoint, config);
if (isDebugMode) {
console.log(
`📡 Response status: ${response.status} ${response.statusText}`
);
}
if (!response.ok) {
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
// Try to get error details from response body
try {
const errorData = await response.text();
if (errorData) {
if (isDebugMode) {
console.log(`[ERROR] Error response body:`, errorData);
}
errorMessage += ` - ${errorData}`;
}
} catch (parseError) {
if (isDebugMode) {
console.log(`[ERROR] Could not parse error response:`, parseError);
}
}
throw new Error(errorMessage);
}
const data = await response.json();
if (isDebugMode) {
console.log(`[SUCCESS] Response data:`, data);
}
return data;
} catch (error) {
// Always log errors for debugging, but make them less verbose in production
if (isDebugMode) {
console.error(`[ERROR] API call failed:`, error);
} else {
console.error(`[ERROR] API call failed: ${error.message}`);
}
throw error;
}
}
/**
* Make a bot management API call
* @param {string} path - API path (e.g., 'get_config_json', 'config')
* @param {string} method - HTTP method
* @param {Object} body - Request body
* @param {Object} headers - Additional headers
* @returns {Promise<Object>} API response
*/
export async function managementApiCall(
path,
method = 'GET',
body = null,
headers = {}
) {
const baseEndpoint = getBotManagementEndpoint();
const fullEndpoint = `${baseEndpoint}/${path}`
.replace(/\/+/g, '/')
.replace('http:/', 'http://')
.replace('https:/', 'https://');
return apiCall(fullEndpoint, method, body, headers);
}
/**
* Make a bot operations API call
* @param {string} path - API path (e.g., 'create_session', 'generate_response')
* @param {string} method - HTTP method
* @param {Object} body - Request body
* @param {Object} headers - Additional headers
* @returns {Promise<Object>} API response
*/
export async function operationsApiCall(
path,
method = 'GET',
body = null,
headers = {}
) {
const baseEndpoint = getBotOperationsEndpoint();
const fullEndpoint = `${baseEndpoint}/${path}`
.replace(/\/+/g, '/')
.replace('http:/', 'http://')
.replace('https:/', 'https://');
return apiCall(fullEndpoint, method, body, headers);
}
/**
* Export legacy function names for backward compatibility
* These will be deprecated in favor of the more specific functions above
*/
// Legacy compatibility exports
export { getBotOperationsEndpoint as getApiEndpoint };
export { getBotManagementEndpoint as getManagementEndpoint };
// Export all endpoints for direct access if needed
export const API_ENDPOINTS = {
getBotOperations: getBotOperationsEndpoint,
getBotManagement: getBotManagementEndpoint,
getRoot: getRootApiEndpoint,
};
// Export constants for external use
export { API_PATHS, getBaseAPIEndpoint };