languages-service.ts•4.87 kB
/**
* Language-related services for the Quran.com API MCP Server
*/
import { z } from 'zod';
import { ApiError } from '../types/error';
import { verboseLog } from '../utils/logger';
import { makeApiRequest } from './base-service';
import { API_BASE_URL, CACHE_DURATION_MS } from '../config';
import { languagesSchema } from '../schemas/languages';
import { LanguagesResponse } from '../types/api-responses';
/**
* Service for language-related API operations
*/
export class LanguagesService {
// Cache for languages list to avoid repeated API calls
private languagesCache: any = null;
private cacheTimestamp: number = 0;
/**
* List Languages
* Get all languages.
*
* @param {Object} params - The parameters for this operation
* @param {string} params.language - Parameter language
* @returns {Promise<LanguagesResponse>} The operation result
* @throws {ApiError} If the operation fails
*/
async listLanguages(params: z.infer<typeof languagesSchema>): Promise<LanguagesResponse> {
try {
// Validate parameters
const validatedParams = languagesSchema.parse(params);
// Check cache first
const now = Date.now();
if (this.languagesCache && (now - this.cacheTimestamp < CACHE_DURATION_MS)) {
verboseLog('response', {
method: 'listLanguages',
source: 'cache',
age: `${(now - this.cacheTimestamp) / 1000} seconds`
});
return {
success: true,
message: "languages executed successfully (from cache)",
data: this.languagesCache
};
}
try {
// Make request to Quran.com API
const url = `${API_BASE_URL}/resources/languages`;
const response = await makeApiRequest(url, {
language: validatedParams.language
});
verboseLog('response', {
method: 'listLanguages',
source: 'api',
dataSize: JSON.stringify(response).length
});
// Update cache
this.languagesCache = response;
this.cacheTimestamp = now;
return {
success: true,
message: "languages executed successfully",
data: response
};
} catch (axiosError) {
verboseLog('error', {
method: 'listLanguages',
error: axiosError instanceof Error ? axiosError.message : String(axiosError)
});
// If the API call fails, return mock data
verboseLog('response', {
method: 'listLanguages',
source: 'mock',
reason: 'API unavailable'
});
const mockData = this.getLanguagesMockData();
return {
success: true,
message: "languages executed with mock data (API unavailable)",
data: mockData
};
}
} catch (error) {
verboseLog('error', {
method: 'listLanguages',
error: error instanceof Error ? error.message : String(error)
});
if (error instanceof z.ZodError) {
throw new ApiError(`Validation error: ${error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')}`, 400);
}
// Return mock data as a fallback for any error
verboseLog('response', {
method: 'listLanguages',
source: 'mock',
reason: 'error occurred'
});
const mockData = this.getLanguagesMockData();
return {
success: true,
message: "languages executed with mock data (error occurred)",
data: mockData
};
}
}
/**
* Get mock data for languages
* @returns Mock languages data
*/
private getLanguagesMockData() {
return {
languages: [
{ id: 1, name: "English", iso_code: "en", native_name: "English", direction: "ltr" },
{ id: 2, name: "Arabic", iso_code: "ar", native_name: "العربية", direction: "rtl" },
{ id: 3, name: "Urdu", iso_code: "ur", native_name: "اردو", direction: "rtl" },
{ id: 4, name: "French", iso_code: "fr", native_name: "Français", direction: "ltr" },
{ id: 5, name: "Spanish", iso_code: "es", native_name: "Español", direction: "ltr" },
{ id: 6, name: "Indonesian", iso_code: "id", native_name: "Bahasa Indonesia", direction: "ltr" },
{ id: 7, name: "Turkish", iso_code: "tr", native_name: "Türkçe", direction: "ltr" },
{ id: 8, name: "Russian", iso_code: "ru", native_name: "Русский", direction: "ltr" },
{ id: 9, name: "German", iso_code: "de", native_name: "Deutsch", direction: "ltr" },
{ id: 10, name: "Malay", iso_code: "ms", native_name: "Bahasa Melayu", direction: "ltr" }
]
};
}
}
// Export a singleton instance
export const languagesService = new LanguagesService();