Skip to content

Commit bf41a1e

Browse files
committed
validate params
1 parent 6943364 commit bf41a1e

File tree

7 files changed

+56
-4
lines changed

7 files changed

+56
-4
lines changed

src/__tests__/routes.test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,10 @@ describe('API Routes', () => {
335335

336336
it('should handle invalid query parameters gracefully', async () => {
337337
const res = await request(app).get('/v1/technologies?invalid=parameter');
338-
expect(res.statusCode).toEqual(200);
339-
expect(Array.isArray(res.body)).toBe(true);
338+
expect(res.statusCode).toEqual(400);
339+
expect(res.body).toHaveProperty('errors');
340+
expect(res.body.errors[0]).toHaveProperty('error');
341+
expect(res.body.errors[0].error).toContain('Unsupported parameters: ');
340342
});
341343
});
342344

src/controllers/categoriesController.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ import { executeQuery, validateArrayParameter } from '../utils/controllerHelpers
66
*/
77
const listCategories = async (req, res) => {
88
const queryBuilder = async (params) => {
9+
// Validate parameters
10+
const supportedParams = ['category', 'onlyname', 'fields'];
11+
const providedParams = Object.keys(params);
12+
const unsupportedParams = providedParams.filter(param => !supportedParams.includes(param));
13+
14+
if (unsupportedParams.length > 0) {
15+
const error = new Error(`Unsupported parameters: ${unsupportedParams.join(', ')}.`);
16+
error.statusCode = 400;
17+
throw error;
18+
}
19+
920
const isOnlyNames = params.onlyname || typeof params.onlyname === 'string';
1021
const hasCustomFields = params.fields && !isOnlyNames;
1122

src/controllers/reportController.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ const createReportController = (reportType) => {
4949
try {
5050
const params = req.query;
5151

52+
// Validate supported parameters
53+
const supportedParams = ['technology', 'geo', 'rank', 'start', 'end'];
54+
const providedParams = Object.keys(params);
55+
const unsupportedParams = providedParams.filter(param => !supportedParams.includes(param));
56+
57+
if (unsupportedParams.length > 0) {
58+
const error = new Error(`Unsupported parameters: ${unsupportedParams.join(', ')}.`);
59+
error.statusCode = 400;
60+
throw error;
61+
}
62+
5263
// Validate required parameters using shared utility
5364
const errors = validateRequiredParams(params, [
5465
REQUIRED_PARAMS.GEO,

src/controllers/technologiesController.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ import { executeQuery, validateTechnologyArray, validateArrayParameter, FIRESTOR
66
*/
77
const listTechnologies = async (req, res) => {
88
const queryBuilder = async (params) => {
9+
// Validate parameters
10+
const supportedParams = ['technology', 'category', 'onlyname', 'fields'];
11+
const providedParams = Object.keys(params);
12+
const unsupportedParams = providedParams.filter(param => !supportedParams.includes(param));
13+
14+
if (unsupportedParams.length > 0) {
15+
const error = new Error(`Unsupported parameters: ${unsupportedParams.join(', ')}.`);
16+
error.statusCode = 400;
17+
throw error;
18+
}
19+
920
const isOnlyNames = params.onlyname || typeof params.onlyname === 'string';
1021
const hasCustomFields = params.fields && !isOnlyNames;
1122

src/controllers/versionsController.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ import { executeQuery, validateTechnologyArray, FIRESTORE_IN_LIMIT } from '../ut
66
*/
77
const listVersions = async (req, res) => {
88
const queryBuilder = async (params) => {
9+
// Validate parameters
10+
const supportedParams = ['version', 'technology', 'category', 'onlyname', 'fields'];
11+
const providedParams = Object.keys(params);
12+
const unsupportedParams = providedParams.filter(param => !supportedParams.includes(param));
13+
14+
if (unsupportedParams.length > 0) {
15+
const error = new Error(`Unsupported parameters: ${unsupportedParams.join(', ')}.`);
16+
error.statusCode = 400;
17+
throw error;
18+
}
19+
920
let query = firestore.collection('versions');
1021

1122
// Apply technology filter with validation

src/utils/controllerHelpers.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,14 @@ const getCacheStats = () => {
230230
*/
231231
const handleControllerError = (res, error, operation) => {
232232
console.error(`Error ${operation}:`, error);
233-
res.statusCode = 500;
233+
const statusCode = error.statusCode || 500;
234+
res.statusCode = statusCode;
235+
236+
// Use custom error message for client errors (4xx), generic message for server errors (5xx)
237+
const errorMessage = statusCode >= 400 && statusCode < 500 ? error.message : `Failed to ${operation}`;
238+
234239
res.end(JSON.stringify({
235-
errors: [{ error: `Failed to ${operation}` }]
240+
errors: [{ error: errorMessage }]
236241
}));
237242
};
238243

test-api.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ test_endpoint "/" ""
8585

8686
# Test technologies endpoint
8787
test_cors_preflight "/v1/technologies"
88+
test_endpoint "/v1/technologies" "?onlyname=true"
8889
test_endpoint "/v1/technologies" "?technology=WordPress&onlyname=true"
8990
test_endpoint "/v1/technologies" "?technology=WordPress&onlyname=true&fields=technology,icon"
9091
test_endpoint "/v1/technologies" "?technology=WordPress&category=CMS&fields=technology,icon"

0 commit comments

Comments
 (0)