diff --git a/src/controllers/azList.controller.js b/src/controllers/azList.controller.js index 31a3d44..0ab23aa 100644 --- a/src/controllers/azList.controller.js +++ b/src/controllers/azList.controller.js @@ -18,6 +18,7 @@ import { extractAzList } from "../extractors/azList.extractor.js"; import { getCache, setCache, TTL } from "../helper/cache.helper.js"; +import { addPaginationMeta } from "../helper/pagination.helper.js"; // ══════════════════════════════════════════════════════════════ // CONTROLLER: A-Z LIST @@ -51,8 +52,9 @@ const getAzList = async (req, res, next) => { return res.json({ success: true, results: cached }); } const data = await extractAzList(letter, page); - setCache(cacheKey, data, TTL.genres); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.genres); + res.json({ success: true, results: response }); } catch (error) { next(error); } diff --git a/src/controllers/category.controller.js b/src/controllers/category.controller.js index 276689c..f7e7e66 100644 --- a/src/controllers/category.controller.js +++ b/src/controllers/category.controller.js @@ -18,6 +18,7 @@ import { extractCategory } from "../extractors/category.extractor.js"; import { getCache, setCache, TTL } from "../helper/cache.helper.js"; +import { addPaginationMeta } from "../helper/pagination.helper.js"; // ══════════════════════════════════════════════════════════════ // CONTROLLER: CATEGORY @@ -55,8 +56,9 @@ const getCategory = async (req, res, next) => { return res.json({ success: true, results: cached }); } const data = await extractCategory(category, page); - setCache(cacheKey, data, TTL.genres); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.genres); + res.json({ success: true, results: response }); } catch (error) { next(error); } diff --git a/src/controllers/filter.controller.js b/src/controllers/filter.controller.js index 0fb3562..a17538c 100644 --- a/src/controllers/filter.controller.js +++ b/src/controllers/filter.controller.js @@ -18,6 +18,7 @@ import { extractFilter } from "../extractors/filter.extractor.js"; import { getCache, setCache, TTL } from "../helper/cache.helper.js"; +import { addPaginationMeta } from "../helper/pagination.helper.js"; // ══════════════════════════════════════════════════════════════ // CONTROLLER: FILTER @@ -47,6 +48,7 @@ import { getCache, setCache, TTL } from "../helper/cache.helper.js"; const getFilter = async (req, res, next) => { try { const params = req.query; + const page = params.page || 1; const cacheKey = `filter_${JSON.stringify(params, Object.keys(params).sort())}`; const cached = getCache(cacheKey); if (cached) { @@ -57,8 +59,9 @@ const getFilter = async (req, res, next) => { if (Array.isArray(params.type)) params.type = params.type.join(","); if (Array.isArray(params.status)) params.status = params.status.join(","); const data = await extractFilter(params); - setCache(cacheKey, data, TTL.genres); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.genres); + res.json({ success: true, results: response }); } catch (error) { next(error); } diff --git a/src/controllers/newRelease.controller.js b/src/controllers/newRelease.controller.js index e15e20d..1c7828a 100644 --- a/src/controllers/newRelease.controller.js +++ b/src/controllers/newRelease.controller.js @@ -19,6 +19,7 @@ import { extractNewRelease, extractNewlyAdded, extractLatestUpdated } from "../extractors/newRelease.extractor.js"; import { getCache, setCache, TTL } from "../helper/cache.helper.js"; +import { addPaginationMeta } from "../helper/pagination.helper.js"; // ══════════════════════════════════════════════════════════════ // CONTROLLER: NEW RELEASE @@ -48,8 +49,9 @@ const getNewRelease = async (req, res, next) => { return res.json({ success: true, results: cached }); } const data = await extractNewRelease(page); - setCache(cacheKey, data, TTL.default); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.default); + res.json({ success: true, results: response }); } catch (error) { next(error); } @@ -83,8 +85,9 @@ const getNewlyAdded = async (req, res, next) => { return res.json({ success: true, results: cached }); } const data = await extractNewlyAdded(page); - setCache(cacheKey, data, TTL.default); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.default); + res.json({ success: true, results: response }); } catch (error) { next(error); } @@ -117,8 +120,9 @@ const getLatestUpdated = async (req, res, next) => { return res.json({ success: true, results: cached }); } const data = await extractLatestUpdated(page); - setCache(cacheKey, data, TTL.default); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.default); + res.json({ success: true, results: response }); } catch (error) { next(error); } diff --git a/src/controllers/popular.controller.js b/src/controllers/popular.controller.js index f69e680..1946329 100644 --- a/src/controllers/popular.controller.js +++ b/src/controllers/popular.controller.js @@ -18,6 +18,7 @@ import { extractPopular } from "../extractors/popular.extractor.js"; import { getCache, setCache, TTL } from "../helper/cache.helper.js"; +import { addPaginationMeta } from "../helper/pagination.helper.js"; // ══════════════════════════════════════════════════════════════ // CONTROLLER: POPULAR @@ -47,8 +48,9 @@ const getPopular = async (req, res, next) => { return res.json({ success: true, results: cached }); } const data = await extractPopular(page); - setCache(cacheKey, data, TTL.default); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.default); + res.json({ success: true, results: response }); } catch (error) { next(error); } diff --git a/src/controllers/search.controller.js b/src/controllers/search.controller.js index 0cef139..0c780b1 100644 --- a/src/controllers/search.controller.js +++ b/src/controllers/search.controller.js @@ -19,6 +19,7 @@ import { extractSearchResults, extractSearchSuggestions } from "../extractors/search.extractor.js"; import { getCache, setCache, TTL } from "../helper/cache.helper.js"; +import { addPaginationMeta } from "../helper/pagination.helper.js"; // ══════════════════════════════════════════════════════════════ // CONTROLLER: SEARCH RESULTS @@ -52,8 +53,9 @@ const getSearchResults = async (req, res, next) => { return res.json({ success: true, results: cached }); } const data = await extractSearchResults(keyword, page); - setCache(cacheKey, data, TTL.search); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.search); + res.json({ success: true, results: response }); } catch (error) { next(error); } diff --git a/src/controllers/status.controller.js b/src/controllers/status.controller.js index 8c108c3..d51a57e 100644 --- a/src/controllers/status.controller.js +++ b/src/controllers/status.controller.js @@ -18,6 +18,7 @@ import { extractStatus } from "../extractors/status.extractor.js"; import { getCache, setCache, TTL } from "../helper/cache.helper.js"; +import { addPaginationMeta } from "../helper/pagination.helper.js"; // ══════════════════════════════════════════════════════════════ // CONTROLLER: STATUS @@ -62,8 +63,9 @@ const getStatus = async (req, res, next) => { }; const mappedStatus = statusMap[status] || status; const data = await extractStatus(mappedStatus, page); - setCache(cacheKey, data, TTL.genres); - res.json({ success: true, results: data }); + const response = addPaginationMeta(data, page); + setCache(cacheKey, response, TTL.genres); + res.json({ success: true, results: response }); } catch (error) { next(error); } diff --git a/src/helper/pagination.helper.js b/src/helper/pagination.helper.js new file mode 100644 index 0000000..34b9ffd --- /dev/null +++ b/src/helper/pagination.helper.js @@ -0,0 +1,59 @@ +/* + * ======= • ======= • ======= • ======= • =======• ======= + * AniKotoAPI — pagination.helper.js + * Repository: https://github.com/Shineii86/AniKotoAPI + * + * @description + * Utility function to add pagination metadata to API responses. + * Provides standardized pagination info for all paginated endpoints. + * + * @exports + * addPaginationMeta + * + * @author Shinei Nouzen + * @license MIT + * ======= • ======= • ======= • ======= • =======• ======= + */ + +/** + * Adds pagination metadata to a response object. + * + * @param {object} data - The data object containing `data` array and optionally `totalPages` + * @param {number} currentPage - Current page number (1-indexed) + * @param {number} [itemsPerPage=30] - Number of items per page + * @returns {object} Object with data and pagination metadata + * + * @example + * const response = addPaginationMeta({ data: [...], totalPages: 5 }, 1, 30); + * // response = { + * // data: [...], + * // pagination: { + * // currentPage: 1, + * // totalPages: 5, + * // totalItems: 150, + * // itemsPerPage: 30, + * // hasNext: true, + * // hasPrev: false + * // } + * // } + */ +const addPaginationMeta = (data, currentPage, itemsPerPage = 30) => { + const totalPages = data.totalPages || 1; + const page = parseInt(currentPage) || 1; + const totalItems = data.data ? data.data.length * totalPages : 0; + + return { + ...data, + pagination: { + currentPage: page, + totalPages: totalPages, + totalItems: totalItems, + itemsPerPage: itemsPerPage, + hasNext: page < totalPages, + hasPrev: page > 1, + }, + }; +}; + +export { addPaginationMeta }; +// ══════════════════════════════════════════════════════════════ END: pagination.helper.js diff --git a/src/middleware/creatorInfo.js b/src/middleware/creatorInfo.js index ae95823..38ada3b 100644 --- a/src/middleware/creatorInfo.js +++ b/src/middleware/creatorInfo.js @@ -61,6 +61,7 @@ const addCreatorInfo = (req, res, next) => { creator: creatorInfo.creator, github: creatorInfo.github, telegram: creatorInfo.telegram, + message: creatorInfo.message, timestamp: new Date().toLocaleString("en-IN", { timeZone: "Asia/Kolkata", hour12: true }), }; }