feat: initialize news service with core functionality
- 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.
This commit is contained in:
78
src/controllers/NewsApiCompatibilityController.js
Normal file
78
src/controllers/NewsApiCompatibilityController.js
Normal file
@@ -0,0 +1,78 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user