- Add package.json for project configuration and dependencies. - Implement NewsApplication class to manage service lifecycle and HTTP pipeline. - Create CategoryCatalog for managing news categories. - Introduce ServiceConfig for environment variable management. - Load environment variables from .env files. - Develop NewsApiCompatibilityController to mimic NewsAPI endpoints. - Create NewsController for querying and refreshing news data. - Establish AbstractJsonRepository for JSON storage operations. - Implement main entry point in index.js to bootstrap the application. - Create CategoryNewsRepository for category-specific news storage. - Add ConsoleLogger for structured logging. - Implement NewsApiClient for fetching articles from NewsAPI. - Develop NewsRefreshScheduler for scheduling news refresh tasks. - Create NewsStorageService to coordinate news data management.
78 lines
2.3 KiB
JavaScript
78 lines
2.3 KiB
JavaScript
const express = require('express')
|
|
|
|
/**
|
|
* NewsApiCompatibilityController
|
|
*
|
|
* Mimics the subset of NewsAPI endpoints currently consumed by the front-end.
|
|
*/
|
|
class NewsApiCompatibilityController {
|
|
constructor(storageService) {
|
|
this._storageService = storageService
|
|
this.router = express.Router()
|
|
this._registerRoutes()
|
|
}
|
|
|
|
/**
|
|
* @returns {void}
|
|
*/
|
|
_registerRoutes() {
|
|
this.router.get('/everything', this._wrap(async (request, response) => {
|
|
const categoryKey = this._normalizeCategoryKey(request.query.q)
|
|
const page = this._parsePositiveInteger(request.query.page, 1)
|
|
const pageSize = this._parsePositiveInteger(request.query.pageSize, 10)
|
|
const document = await this._storageService.getCategoryNewsPage(categoryKey, page, pageSize)
|
|
|
|
response.json({
|
|
status: 'ok',
|
|
totalResults: document.total,
|
|
articles: document.articles
|
|
})
|
|
}))
|
|
|
|
this.router.get('/top-headlines', this._wrap(async (request, response) => {
|
|
const categoryKey = this._normalizeCategoryKey(request.query.category || 'business')
|
|
const page = this._parsePositiveInteger(request.query.page, 1)
|
|
const pageSize = this._parsePositiveInteger(request.query.pageSize, 10)
|
|
const document = await this._storageService.getCategoryNewsPage(categoryKey, page, pageSize)
|
|
|
|
response.json({
|
|
status: 'ok',
|
|
totalResults: document.total,
|
|
articles: document.articles
|
|
})
|
|
}))
|
|
}
|
|
|
|
/**
|
|
* @param {unknown} value
|
|
* @returns {string}
|
|
*/
|
|
_normalizeCategoryKey(value) {
|
|
const categoryKey = String(value || 'finance').trim().toLowerCase()
|
|
return categoryKey
|
|
}
|
|
|
|
/**
|
|
* @param {unknown} value
|
|
* @param {number} fallback
|
|
* @returns {number}
|
|
*/
|
|
_parsePositiveInteger(value, fallback) {
|
|
const parsed = Number(value)
|
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
|
|
}
|
|
|
|
/**
|
|
* @param {(request: import('express').Request, response: import('express').Response) => Promise<void>} handler
|
|
* @returns {(request: import('express').Request, response: import('express').Response, next: import('express').NextFunction) => void}
|
|
*/
|
|
_wrap(handler) {
|
|
return (request, response, next) => {
|
|
handler(request, response).catch(next)
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
NewsApiCompatibilityController
|
|
} |