From 4381c8682caab77f3e1ecd6092cff3c3fc324a1e Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Wed, 18 Mar 2026 10:25:09 +0000 Subject: [PATCH 1/3] fix(IPA-110): relax itemsPerPage validation to require default > 1 Instead of enforcing an exact default of 100, the rule now accepts any default value greater than 1, allowing APIs to define their own reasonable page sizes. Co-Authored-By: Claude Code --- ...nsRequestHasItemsPerPageQueryParam.test.js | 86 ++++++++++++++++++- ...ectionsRequestHasItemsPerPageQueryParam.js | 2 +- ...PaginationQueryParameterAndReturnErrors.js | 17 +++- 3 files changed, 98 insertions(+), 7 deletions(-) diff --git a/tools/spectral/ipa/__tests__/IPA110CollectionsRequestHasItemsPerPageQueryParam.test.js b/tools/spectral/ipa/__tests__/IPA110CollectionsRequestHasItemsPerPageQueryParam.test.js index 5e47272e41..1c31e4d374 100644 --- a/tools/spectral/ipa/__tests__/IPA110CollectionsRequestHasItemsPerPageQueryParam.test.js +++ b/tools/spectral/ipa/__tests__/IPA110CollectionsRequestHasItemsPerPageQueryParam.test.js @@ -61,6 +61,56 @@ testRule('xgen-IPA-110-collections-request-has-itemsPerPage-query-param', [ }, errors: [], }, + { + name: 'valid - non-100 default value greater than 1', + document: { + paths: { + '/resources': { + get: { + parameters: [ + { + name: 'itemsPerPage', + in: 'query', + schema: { + type: 'integer', + default: 50, + }, + }, + ], + }, + }, + 'resources/{resourceId}': { + get: {}, + }, + }, + }, + errors: [], + }, + { + name: 'valid - minimum allowed default value of 2', + document: { + paths: { + '/resources': { + get: { + parameters: [ + { + name: 'itemsPerPage', + in: 'query', + schema: { + type: 'integer', + default: 2, + }, + }, + ], + }, + }, + 'resources/{resourceId}': { + get: {}, + }, + }, + }, + errors: [], + }, { name: 'invalid - missing parameters', document: { @@ -195,7 +245,7 @@ testRule('xgen-IPA-110-collections-request-has-itemsPerPage-query-param', [ ], }, { - name: 'invalid - wrong default value', + name: 'invalid - default value of 0', document: { paths: { '/resources': { @@ -220,7 +270,39 @@ testRule('xgen-IPA-110-collections-request-has-itemsPerPage-query-param', [ errors: [ { code: 'xgen-IPA-110-collections-request-has-itemsPerPage-query-param', - message: 'itemsPerPage query parameter of List method must have a default value of 100.', + message: 'itemsPerPage query parameter of List method must have a default value greater than 1.', + path: ['paths', '/resources', 'get'], + severity: DiagnosticSeverity.Error, + }, + ], + }, + { + name: 'invalid - default value of 1', + document: { + paths: { + '/resources': { + get: { + parameters: [ + { + name: 'itemsPerPage', + in: 'query', + schema: { + type: 'integer', + default: 1, + }, + }, + ], + }, + }, + 'resources/{resourceId}': { + get: {}, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-110-collections-request-has-itemsPerPage-query-param', + message: 'itemsPerPage query parameter of List method must have a default value greater than 1.', path: ['paths', '/resources', 'get'], severity: DiagnosticSeverity.Error, }, diff --git a/tools/spectral/ipa/rulesets/functions/IPA110CollectionsRequestHasItemsPerPageQueryParam.js b/tools/spectral/ipa/rulesets/functions/IPA110CollectionsRequestHasItemsPerPageQueryParam.js index 6e3eb2d5b8..34c79721e9 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA110CollectionsRequestHasItemsPerPageQueryParam.js +++ b/tools/spectral/ipa/rulesets/functions/IPA110CollectionsRequestHasItemsPerPageQueryParam.js @@ -18,6 +18,6 @@ export default (input, _, { path, documentInventory, rule }) => { return; } - const errors = checkPaginationQueryParameterAndReturnErrors(input, path, 'itemsPerPage', 100, ruleName); + const errors = checkPaginationQueryParameterAndReturnErrors(input, path, 'itemsPerPage', { min: 1 }, ruleName); return evaluateAndCollectAdoptionStatus(errors, ruleName, input, path); }; diff --git a/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js b/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js index aef35a5ef4..02fe510ae3 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js +++ b/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js @@ -6,11 +6,11 @@ import { handleInternalError } from '../collectionUtils.js'; * @param {Object} operation - The OpenAPI operation object to check * @param {string[]} path - The path to the operation * @param {string} paramName - The name of the parameter to check ('pageNum' or 'itemsPerPage') - * @param {number} defaultValue - The expected default value (1 for pageNum, 100 for itemsPerPage) + * @param {number|{min: number}} defaultConstraint - The expected default value (exact match), or an object with a `min` property for a minimum value check * @param {string} ruleName - The rule name for error handling * @returns {Array} - Array of error objects or empty array if no errors */ -export function checkPaginationQueryParameterAndReturnErrors(operation, path, paramName, defaultValue, ruleName) { +export function checkPaginationQueryParameterAndReturnErrors(operation, path, paramName, defaultConstraint, ruleName) { try { const parameters = operation.parameters; @@ -54,11 +54,20 @@ export function checkPaginationQueryParameterAndReturnErrors(operation, path, pa ]; } - if (param.schema.default !== defaultValue) { + if (typeof defaultConstraint === 'object' && defaultConstraint !== null && 'min' in defaultConstraint) { + if (param.schema.default <= defaultConstraint.min) { + return [ + { + path, + message: `${paramName} query parameter of List method must have a default value greater than ${defaultConstraint.min}.`, + }, + ]; + } + } else if (param.schema.default !== defaultConstraint) { return [ { path, - message: `${paramName} query parameter of List method must have a default value of ${defaultValue}.`, + message: `${paramName} query parameter of List method must have a default value of ${defaultConstraint}.`, }, ]; } From bb3a0ee82ef36786cd226e05bcfeaf49056fedb2 Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Wed, 18 Mar 2026 21:10:28 +0000 Subject: [PATCH 2/3] refactor: unify defaultConstraint to always be an object Replace the mixed number|{min} parameter type with a consistent object shape: { value: N } for exact match, { min: N } for range check. Co-Authored-By: Claude Code --- .../IPA110CollectionsRequestHasPageNumQueryParam.js | 2 +- .../checkPaginationQueryParameterAndReturnErrors.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA110CollectionsRequestHasPageNumQueryParam.js b/tools/spectral/ipa/rulesets/functions/IPA110CollectionsRequestHasPageNumQueryParam.js index 218f1014b9..0e8cef95b1 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA110CollectionsRequestHasPageNumQueryParam.js +++ b/tools/spectral/ipa/rulesets/functions/IPA110CollectionsRequestHasPageNumQueryParam.js @@ -18,6 +18,6 @@ export default (input, _, { path, documentInventory, rule }) => { return; } - const errors = checkPaginationQueryParameterAndReturnErrors(input, path, 'pageNum', 1, ruleName); + const errors = checkPaginationQueryParameterAndReturnErrors(input, path, 'pageNum', { value: 1 }, ruleName); return evaluateAndCollectAdoptionStatus(errors, ruleName, input, path); }; diff --git a/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js b/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js index 02fe510ae3..91375956e6 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js +++ b/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js @@ -6,7 +6,7 @@ import { handleInternalError } from '../collectionUtils.js'; * @param {Object} operation - The OpenAPI operation object to check * @param {string[]} path - The path to the operation * @param {string} paramName - The name of the parameter to check ('pageNum' or 'itemsPerPage') - * @param {number|{min: number}} defaultConstraint - The expected default value (exact match), or an object with a `min` property for a minimum value check + * @param {{value: number}|{min: number}} defaultConstraint - Either `{ value: N }` for an exact match, or `{ min: N }` for a minimum value check * @param {string} ruleName - The rule name for error handling * @returns {Array} - Array of error objects or empty array if no errors */ @@ -54,7 +54,7 @@ export function checkPaginationQueryParameterAndReturnErrors(operation, path, pa ]; } - if (typeof defaultConstraint === 'object' && defaultConstraint !== null && 'min' in defaultConstraint) { + if ('min' in defaultConstraint) { if (param.schema.default <= defaultConstraint.min) { return [ { @@ -63,11 +63,11 @@ export function checkPaginationQueryParameterAndReturnErrors(operation, path, pa }, ]; } - } else if (param.schema.default !== defaultConstraint) { + } else if (param.schema.default !== defaultConstraint.value) { return [ { path, - message: `${paramName} query parameter of List method must have a default value of ${defaultConstraint}.`, + message: `${paramName} query parameter of List method must have a default value of ${defaultConstraint.value}.`, }, ]; } From 79b94ced35e57db8d3d7d051555d11b5158637d7 Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Thu, 19 Mar 2026 10:36:59 +0000 Subject: [PATCH 3/3] refactor: add max support and rename defaultConstraint to constraint - Rename defaultConstraint to constraint for clarity - Add { max: N } support for upper-bound checks - Validate that range constraints have at least min or max set Co-Authored-By: Claude Code --- ...PaginationQueryParameterAndReturnErrors.js | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js b/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js index 91375956e6..9c9c6df13b 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js +++ b/tools/spectral/ipa/rulesets/functions/utils/validations/checkPaginationQueryParameterAndReturnErrors.js @@ -6,11 +6,11 @@ import { handleInternalError } from '../collectionUtils.js'; * @param {Object} operation - The OpenAPI operation object to check * @param {string[]} path - The path to the operation * @param {string} paramName - The name of the parameter to check ('pageNum' or 'itemsPerPage') - * @param {{value: number}|{min: number}} defaultConstraint - Either `{ value: N }` for an exact match, or `{ min: N }` for a minimum value check + * @param {{value: number}|{min?: number, max?: number}} constraint - Either `{ value: N }` for an exact match, or `{ min: N, max: N }` for a range check (min and max are both optional) * @param {string} ruleName - The rule name for error handling * @returns {Array} - Array of error objects or empty array if no errors */ -export function checkPaginationQueryParameterAndReturnErrors(operation, path, paramName, defaultConstraint, ruleName) { +export function checkPaginationQueryParameterAndReturnErrors(operation, path, paramName, constraint, ruleName) { try { const parameters = operation.parameters; @@ -54,22 +54,35 @@ export function checkPaginationQueryParameterAndReturnErrors(operation, path, pa ]; } - if ('min' in defaultConstraint) { - if (param.schema.default <= defaultConstraint.min) { + if ('value' in constraint) { + if (param.schema.default !== constraint.value) { return [ { path, - message: `${paramName} query parameter of List method must have a default value greater than ${defaultConstraint.min}.`, + message: `${paramName} query parameter of List method must have a default value of ${constraint.value}.`, + }, + ]; + } + } else { + if (!('min' in constraint) && !('max' in constraint)) { + throw new Error(`constraint must have either 'value', 'min', or 'max'`); + } + if ('min' in constraint && param.schema.default <= constraint.min) { + return [ + { + path, + message: `${paramName} query parameter of List method must have a default value greater than ${constraint.min}.`, + }, + ]; + } + if ('max' in constraint && param.schema.default > constraint.max) { + return [ + { + path, + message: `${paramName} query parameter of List method must have a default value less than or equal to ${constraint.max}.`, }, ]; } - } else if (param.schema.default !== defaultConstraint.value) { - return [ - { - path, - message: `${paramName} query parameter of List method must have a default value of ${defaultConstraint.value}.`, - }, - ]; } return [];