Skip to main content
Glama

News Aggregator API

article.service.ts6.06 kB
/** * Article service for managing article data */ import { Article } from '../models/prisma.types'; import { repositoryFactory } from '../repositories'; import { logger } from '../utils/logger'; import { NewsApiResponse, NewsArticle, SingleArticleResponse } from '../models/news.model'; /** * Service for managing article data */ export class ArticleService { private articleRepository = repositoryFactory.getArticleRepository(); /** * Save articles from API response to database * @param apiResponse Response from News API * @returns Number of articles saved */ async saveArticlesFromApiResponse(apiResponse: NewsApiResponse): Promise<number> { try { let savedCount = 0; // Process each article in the API response for (const article of apiResponse.data) { await this.saveArticleFromApiData(article); savedCount++; } logger.info(`Saved ${savedCount} articles to database`); return savedCount; } catch (error) { logger.error('Error saving articles from API response:', error); throw error; } } /** * Save single article from API response to database * @param apiArticle Article data from API * @returns Saved article */ async saveArticleFromApiData(apiArticle: NewsArticle): Promise<Article> { try { // Check if article already exists const existingArticle = await this.articleRepository.findByUuid(apiArticle.uuid); if (existingArticle) { // Update existing article return await this.articleRepository.update(existingArticle.id, { title: apiArticle.title, description: apiArticle.description || null, url: apiArticle.url, imageUrl: apiArticle.image_url || null, publishedAt: new Date(apiArticle.published_at), updatedAt: new Date() }); } else { // Create new article return await this.articleRepository.create({ uuid: apiArticle.uuid, title: apiArticle.title, description: apiArticle.description || null, url: apiArticle.url, imageUrl: apiArticle.image_url || null, source: apiArticle.source, publishedAt: new Date(apiArticle.published_at), categories: Array.isArray(apiArticle.categories) ? apiArticle.categories.join(',') : '', language: apiArticle.language, readCount: 0, relevanceScore: apiArticle.relevance_score || null, sentiment: null // To be filled by sentiment analysis later }); } } catch (error) { logger.error(`Error saving article ${apiArticle.uuid}:`, error); throw error; } } /** * Save single article from UUID API response * @param apiArticle Article data from UUID API * @returns Saved article */ async saveArticleFromUuidResponse(apiArticle: SingleArticleResponse): Promise<Article> { try { // Convert SingleArticleResponse to the format needed for saving const articleData: NewsArticle = { uuid: apiArticle.uuid, title: apiArticle.title, description: apiArticle.description, keywords: apiArticle.keywords, snippet: apiArticle.snippet, url: apiArticle.url, image_url: apiArticle.image_url, language: apiArticle.language, published_at: apiArticle.published_at, source: apiArticle.source, categories: apiArticle.categories, relevance_score: null, locale: apiArticle.language // Use language as locale if not provided }; return await this.saveArticleFromApiData(articleData); } catch (error) { logger.error(`Error saving article from UUID response ${apiArticle.uuid}:`, error); throw error; } } /** * Get article by UUID * @param uuid Article UUID * @returns Article or null if not found */ async getArticleByUuid(uuid: string): Promise<Article | null> { try { return await this.articleRepository.findByUuid(uuid); } catch (error) { logger.error(`Error getting article by UUID ${uuid}:`, error); throw error; } } /** * Get recent articles * @param limit Maximum number of articles to return * @returns Array of recent articles */ async getRecentArticles(limit: number = 10): Promise<Article[]> { try { const result = await this.articleRepository.search({ take: limit, orderBy: { publishedAt: 'desc' } }); return result.items; } catch (error) { logger.error('Error getting recent articles:', error); throw error; } } /** * Get articles by category * @param category Article category * @param limit Maximum number of articles to return * @returns Array of articles in the specified category */ async getArticlesByCategory(category: string, limit: number = 10): Promise<Article[]> { try { return await this.articleRepository.findByCategory(category, limit); } catch (error) { logger.error(`Error getting articles by category ${category}:`, error); throw error; } } /** * Get similar articles * @param articleId Article ID to find similar articles for * @param limit Maximum number of similar articles to return * @returns Array of similar articles */ async getSimilarArticles(articleId: number, limit: number = 5): Promise<Article[]> { try { return await this.articleRepository.findSimilarArticles(articleId, limit); } catch (error) { logger.error(`Error getting similar articles for article ${articleId}:`, error); throw error; } } /** * Track article view * @param articleId Article ID * @returns Updated article */ async trackArticleView(articleId: number): Promise<Article> { try { return await this.articleRepository.incrementReadCount(articleId); } catch (error) { logger.error(`Error tracking view for article ${articleId}:`, error); throw error; } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Malachi-devel/the-news-api-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server