-
Notifications
You must be signed in to change notification settings - Fork 691
feat: add pagination middleware for resume routes (#515) #642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { asyncHandler } from './errorHandler.js'; | ||
|
|
||
| /** | ||
| * Pagination middleware | ||
| * Reads page, limit, sort from query params | ||
| * Attaches pagination helpers to req.paginate | ||
| * Usage: router.get('/', verifyToken, paginate(), asyncHandler(...)) | ||
| */ | ||
| export const paginate = () => | ||
| asyncHandler(async (req, res, next) => { | ||
| // Parse page (default 1, minimum 1) | ||
| const page = Math.max(1, parseInt(req.query.page) || 1); | ||
|
|
||
| // Parse limit (default 10, max 100) | ||
| const limit = Math.min(100, Math.max(1, parseInt(req.query.limit) || 10)); | ||
|
|
||
| // Parse sort field and direction | ||
| // Usage: ?sort=createdAt or ?sort=-createdAt (minus = descending) | ||
| const sortParam = req.query.sort || '-createdAt'; | ||
| const sortOrder = sortParam.startsWith('-') ? -1 : 1; | ||
| const sortField = sortParam.replace(/^-/, ''); | ||
|
|
||
|
Comment on lines
+19
to
+22
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: In Express 4.x, when a query string contains repeated keys (e.g.,?sort=-createdAt&sort=title), the type of req.query.sort is typically an Array of strings [1][2][3]. This behavior is provided by the default "extended" query parser, which uses the qs library under the hood [1][4]. Because req.query can contain strings, arrays, or nested objects depending on the input, it is a best practice to verify the type of the property before accessing it (e.g., checking if it is an array) to avoid runtime errors [4]. Important Version Note: In Express version 4.22.0 and 4.22.1, a regression occurred where the qs library's default arrayLimit of 20 caused repeated keys to be parsed as an object (e.g., { "0": "value1", "1": "value2" }) instead of an array when more than 20 values were provided [1][5]. This was resolved in Express 4.22.2, which restored the expected behavior of returning an array for repeated keys regardless of the count [1][5]. Citations:
🏁 Script executed: # Check if the file exists and read the relevant section
ls -la backend/src/middleware/paginate.js 2>&1 || echo "File not found"Repository: anurag3407/career-pilot Length of output: 151 🏁 Script executed: # Read lines around 19-22 to verify the actual code
head -30 backend/src/middleware/paginate.js | cat -nRepository: anurag3407/career-pilot Length of output: 1278 🏁 Script executed: # Check if similar issues exist with page and limit parameters
cat -n backend/src/middleware/paginate.js | sed -n '11,16p'Repository: anurag3407/career-pilot Length of output: 333 Harden sort parsing against non-string query values. Line 20 can throw when Proposed fix- const sortParam = req.query.sort || '-createdAt';
- const sortOrder = sortParam.startsWith('-') ? -1 : 1;
- const sortField = sortParam.replace(/^-/, '');
+ const rawSort = Array.isArray(req.query.sort) ? req.query.sort[0] : req.query.sort;
+ const sortParam = typeof rawSort === 'string' && rawSort.trim() ? rawSort.trim() : '-createdAt';
+ const sortOrder = sortParam.startsWith('-') ? -1 : 1;
+ const sortField = sortParam.replace(/^-/, '') || 'createdAt';🤖 Prompt for AI Agents |
||
| const skip = (page - 1) * limit; | ||
|
|
||
| // Attach to req so route handlers can use it | ||
| req.paginate = { | ||
| page, | ||
| limit, | ||
| skip, | ||
| sort: { [sortField]: sortOrder } | ||
| }; | ||
|
|
||
| next(); | ||
| }); | ||
|
|
||
| /** | ||
| * Helper to build consistent paginated response | ||
| * Call this inside your route handler to send the response | ||
| */ | ||
| export const paginatedResponse = (res, { data, total, page, limit }) => { | ||
| const totalPages = Math.ceil(total / limit); | ||
|
|
||
| res.json({ | ||
| success: true, | ||
| data, | ||
| meta: { | ||
| total, | ||
| page, | ||
| limit, | ||
| totalPages, | ||
| hasNextPage: page < totalPages, | ||
| hasPrevPage: page > 1 | ||
| } | ||
| }); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate
GEMINI_API_KEYdefinition.GEMINI_API_KEYis already defined on line 8. Having duplicate keys in environment files causes the last occurrence to override earlier ones, leading to configuration confusion. Developers may set the value on line 8 expecting it to work, unaware that line 35 silently overrides it.🔧 Proposed fix
If the intent is to provide a dummy value for local development, update line 8 instead:
And remove line 35:
LINKEDIN_REDIRECT_URI=http://localhost:5000/api/auth/linkedin/callback -GEMINI_API_KEY=dummy-key-for-local-dev🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 35-35: [DuplicatedKey] The GEMINI_API_KEY key is duplicated
(DuplicatedKey)
[warning] 35-35: [UnorderedKey] The GEMINI_API_KEY key should go before the LINKEDIN_CLIENT_ID key
(UnorderedKey)
🤖 Prompt for AI Agents