news.service.ts•9.04 kB
/**
* News service for interacting with The News API
*/
import axios, { AxiosResponse } from 'axios';
import { NewsApiParams, NewsApiResponse, SingleArticleResponse, SourcesApiParams, SourcesApiResponse } from '../models/news.model';
import { newsApiConfig } from '../config/api.config';
import { logger } from '../utils/logger';
import { cacheService } from '../utils/cache';
/**
* Service for fetching news data from The News API
*/
export class NewsService {
/**
* Fetch top news articles based on provided parameters
* @param params Query parameters for the API request
* @returns Promise with the news API response
*/
async getTopNews(params: Omit<NewsApiParams, 'api_token'>): Promise<NewsApiResponse> {
try {
// Generate cache key based on params
const cacheKey = `top_news_${JSON.stringify(params)}`;
// Check if data is in cache
const cachedData = cacheService.get<NewsApiResponse>(cacheKey);
if (cachedData) {
logger.info('Returning cached top news');
return cachedData;
}
// Combine parameters with API token and ensure English language
const queryParams: NewsApiParams = {
...params,
language: 'en', // Default to English language
api_token: newsApiConfig.apiToken
};
// Make request to external API
const url = `${newsApiConfig.baseUrl}${newsApiConfig.endpoints.top}`;
logger.info(`Fetching top news from: ${url}`);
const response: AxiosResponse<NewsApiResponse> = await axios.get(url, {
params: queryParams
});
// Cache the response data
const ttl = cacheService.getTTL('top');
cacheService.set(cacheKey, response.data, ttl);
logger.debug(`Cached top news data with TTL: ${ttl}s`);
return response.data;
} catch (error) {
logger.error('Error fetching top news:', error);
throw new Error(`Failed to fetch top news: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Fetch all news articles based on provided parameters
* @param params Query parameters for the API request
* @returns Promise with the news API response
*/
async getAllNews(params: Omit<NewsApiParams, 'api_token'>): Promise<NewsApiResponse> {
try {
// Generate cache key based on params
const cacheKey = `all_news_${JSON.stringify(params)}`;
// Check if data is in cache
const cachedData = cacheService.get<NewsApiResponse>(cacheKey);
if (cachedData) {
logger.info('Returning cached all news');
return cachedData;
}
// Combine parameters with API token and ensure English language
const queryParams: NewsApiParams = {
...params,
language: 'en', // Default to English language
api_token: newsApiConfig.apiToken
};
// Make request to external API
const url = `${newsApiConfig.baseUrl}${newsApiConfig.endpoints.all}`;
logger.info(`Fetching all news from: ${url}`);
const response: AxiosResponse<NewsApiResponse> = await axios.get(url, {
params: queryParams
});
// Cache the response data
const ttl = cacheService.getTTL('all');
cacheService.set(cacheKey, response.data, ttl);
logger.debug(`Cached all news data with TTL: ${ttl}s`);
return response.data;
} catch (error) {
logger.error('Error fetching all news:', error);
throw new Error(`Failed to fetch all news: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Fetch similar news articles to a specific article by UUID
* @param uuid UUID of the article to find similar news for
* @param params Query parameters for the API request
* @returns Promise with the news API response
*/
async getSimilarNews(uuid: string, params: Omit<NewsApiParams, 'api_token'>): Promise<NewsApiResponse> {
try {
// Validate UUID format
if (!uuid || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(uuid)) {
throw new Error('Invalid UUID format');
}
// Generate cache key based on UUID and params
const cacheKey = `similar_news_${uuid}_${JSON.stringify(params)}`;
// Check if data is in cache
const cachedData = cacheService.get<NewsApiResponse>(cacheKey);
if (cachedData) {
logger.info(`Returning cached similar news for UUID ${uuid}`);
return cachedData;
}
// Combine parameters with API token and ensure English language
const queryParams: NewsApiParams = {
...params,
language: 'en', // Default to English language
api_token: newsApiConfig.apiToken
};
// Make request to external API
const url = `${newsApiConfig.baseUrl}${newsApiConfig.endpoints.similar.replace('{uuid}', uuid)}`;
logger.info(`Fetching similar news for UUID ${uuid} from: ${url}`);
const response: AxiosResponse<NewsApiResponse> = await axios.get(url, {
params: queryParams
});
// Cache the response data with longer TTL as similar articles rarely change
const ttl = cacheService.getTTL('similar');
cacheService.set(cacheKey, response.data, ttl);
logger.debug(`Cached similar news data for UUID ${uuid} with TTL: ${ttl}s`);
return response.data;
} catch (error) {
logger.error(`Error fetching similar news for UUID ${uuid}:`, error);
throw new Error(`Failed to fetch similar news: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Fetch a specific news article by UUID
* @param uuid UUID of the article to retrieve
* @returns Promise with the single article response
*/
async getNewsByUuid(uuid: string): Promise<SingleArticleResponse> {
try {
// Validate UUID format
if (!uuid || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(uuid)) {
throw new Error('Invalid UUID format');
}
// Generate cache key based on UUID
const cacheKey = `news_article_${uuid}`;
// Check if data is in cache
const cachedData = cacheService.get<SingleArticleResponse>(cacheKey);
if (cachedData) {
logger.info(`Returning cached news article with UUID ${uuid}`);
return cachedData;
}
// Make request to external API
const url = `${newsApiConfig.baseUrl}${newsApiConfig.endpoints.uuid.replace('{uuid}', uuid)}`;
logger.info(`Fetching news article with UUID ${uuid} from: ${url}`);
const response: AxiosResponse<SingleArticleResponse> = await axios.get(url, {
params: {
api_token: newsApiConfig.apiToken
}
});
// Cache the response data with long TTL as specific article content doesn't change
const ttl = cacheService.getTTL('uuid');
cacheService.set(cacheKey, response.data, ttl);
logger.debug(`Cached news article with UUID ${uuid} with TTL: ${ttl}s`);
return response.data;
} catch (error) {
logger.error(`Error fetching news article with UUID ${uuid}:`, error);
throw new Error(`Failed to fetch news article: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Fetch available news sources with optional filtering
* @param params Query parameters for the API request
* @returns Promise with the sources API response
*/
async getNewsSources(params: Omit<SourcesApiParams, 'api_token'>): Promise<SourcesApiResponse> {
try {
// Generate cache key based on params
const cacheKey = `news_sources_${JSON.stringify(params)}`;
// Check if data is in cache
const cachedData = cacheService.get<SourcesApiResponse>(cacheKey);
if (cachedData) {
logger.info('Returning cached news sources');
return cachedData;
}
// Combine parameters with API token and ensure English language if not specified
const queryParams: SourcesApiParams = {
...params,
language: params.language || 'en', // Default to English language if not specified
api_token: newsApiConfig.apiToken
};
// Make request to external API
const url = `${newsApiConfig.baseUrl}${newsApiConfig.endpoints.sources}`;
logger.info(`Fetching news sources from: ${url}`);
const response: AxiosResponse<SourcesApiResponse> = await axios.get(url, {
params: queryParams
});
// Cache the response data with long TTL as sources don't change often
const ttl = cacheService.getTTL('sources');
cacheService.set(cacheKey, response.data, ttl);
logger.debug(`Cached news sources data with TTL: ${ttl}s`);
return response.data;
} catch (error) {
logger.error('Error fetching news sources:', error);
throw new Error(`Failed to fetch news sources: ${error instanceof Error ? error.message : String(error)}`);
}
}
}