Skip to content

Commit 041abf5

Browse files
CLOUDP-304963: IPA-114: Errors (check for 404 codes for parameterized endpoints)
1 parent 1a395af commit 041abf5

File tree

4 files changed

+207
-0
lines changed

4 files changed

+207
-0
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import testRule from './__helpers__/testRule.js';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
testRule('xgen-IPA-114-parameterized-paths-have-404-not-found', [
5+
{
6+
name: 'valid parameterized path with 404 response',
7+
document: {
8+
paths: {
9+
'/resources/{resourceId}': {
10+
get: {
11+
responses: {
12+
200: { description: 'Success' },
13+
404: { description: 'Not Found' },
14+
},
15+
},
16+
},
17+
},
18+
},
19+
errors: [],
20+
},
21+
{
22+
name: 'invalid parameterized path missing 404 response',
23+
document: {
24+
paths: {
25+
'/resources/{resourceId}': {
26+
get: {
27+
responses: {
28+
200: { description: 'Success' },
29+
},
30+
},
31+
},
32+
},
33+
},
34+
errors: [
35+
{
36+
code: 'xgen-IPA-114-parameterized-paths-have-404-not-found',
37+
message: 'Parameterized path must define a 404 response.',
38+
path: ['paths', '/resources/{resourceId}', 'get'],
39+
severity: DiagnosticSeverity.Warning,
40+
},
41+
],
42+
},
43+
{
44+
name: 'non-parameterized path without 404 response (valid)',
45+
document: {
46+
paths: {
47+
'/resources': {
48+
get: {
49+
responses: {
50+
200: { description: 'Success' },
51+
},
52+
},
53+
},
54+
},
55+
},
56+
errors: [],
57+
},
58+
{
59+
name: 'parameterized path with multiple parameters and 404 response',
60+
document: {
61+
paths: {
62+
'/resources/{resourceId}/items/{itemId}': {
63+
get: {
64+
responses: {
65+
200: { description: 'Success' },
66+
404: { description: 'Not Found' },
67+
},
68+
},
69+
},
70+
},
71+
},
72+
errors: [],
73+
},
74+
{
75+
name: 'no responses',
76+
document: {
77+
paths: {
78+
'/resources/{resourceId}': {
79+
get: {},
80+
},
81+
},
82+
},
83+
errors: [
84+
{
85+
code: 'xgen-IPA-114-parameterized-paths-have-404-not-found',
86+
message: 'Parameterized path must define a 404 response.',
87+
path: ['paths', '/resources/{resourceId}', 'get'],
88+
severity: DiagnosticSeverity.Warning,
89+
},
90+
],
91+
},
92+
{
93+
name: 'with exception',
94+
document: {
95+
paths: {
96+
'/resources/{resourceId}': {
97+
get: {
98+
'x-xgen-IPA-exception': {
99+
'xgen-IPA-114-parameterized-paths-have-404-not-found': 'Reason',
100+
},
101+
responses: {
102+
200: { description: 'Success' },
103+
},
104+
},
105+
},
106+
},
107+
},
108+
errors: [],
109+
},
110+
]);

tools/spectral/ipa/rulesets/IPA-114.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ functions:
55
- IPA114ErrorResponsesReferToApiError
66
- IPA114ApiErrorHasBadRequestDetail
77
- IPA114AuthenticatedEndpointsHaveAuthErrors
8+
- IPA114ParameterizedPathsHave404NotFound
89

910
rules:
1011
xgen-IPA-114-error-responses-refer-to-api-error:
@@ -45,3 +46,16 @@ rules:
4546
given: '$.paths[*][*]'
4647
then:
4748
function: 'IPA114AuthenticatedEndpointsHaveAuthErrors'
49+
xgen-IPA-114-parameterized-paths-have-404-not-found:
50+
description: |
51+
Paths with parameters must define 404 responses.
52+
53+
##### Implementation details
54+
This rule checks that all endpoints with path parameters (identified by '{param}'
55+
in the path) include a 404 response to handle the case when the requested resource
56+
is not found.
57+
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-114-parameterized-paths-have-not-found'
58+
severity: warn
59+
given: '$.paths[*][get,put,post,delete,options,head,patch,trace]'
60+
then:
61+
function: 'IPA114ParameterizedPathsHave404NotFound'

tools/spectral/ipa/rulesets/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,16 @@ Authenticated endpoints must define 401 and 403 responses.
636636
This rule checks that all authenticated endpoints (those without explicit 'security: []'
637637
and not containing '/unauth' in the path) include 401 and 403 responses.
638638

639+
#### xgen-IPA-114-parameterized-paths-have-404-not-found
640+
641+
![warn](https://img.shields.io/badge/warning-yellow)
642+
Paths with parameters must define 404 responses.
643+
644+
##### Implementation details
645+
This rule checks that all endpoints with path parameters (identified by '{param}'
646+
in the path) include a 404 response to handle the case when the requested resource
647+
is not found.
648+
639649

640650

641651
### IPA-117
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { hasException } from './utils/exceptions.js';
2+
import {
3+
collectAdoption,
4+
collectAndReturnViolation,
5+
collectException,
6+
handleInternalError,
7+
} from './utils/collectionUtils.js';
8+
9+
const RULE_NAME = 'xgen-IPA-114-parameterized-paths-have-404-not-found';
10+
const ERROR_MESSAGE = `Parameterized path must define a 404 response.`;
11+
/**
12+
* Validates that paths with parameters include a 404 response
13+
*
14+
* @param {object} input - The operation object to check
15+
* @param {object} _ - Rule options (unused)
16+
* @param {object} context - The context object containing path and document information
17+
*/
18+
export default (input, _, { path }) => {
19+
// Path components: [paths, pathName, methodName, ...]
20+
const pathName = path[1];
21+
22+
const pathParamRegex = /{[^{}]+}/;
23+
if (!pathParamRegex.test(pathName)) {
24+
return;
25+
}
26+
27+
// Check for exception at operation level
28+
if (hasException(input, RULE_NAME)) {
29+
collectException(input, RULE_NAME, path);
30+
return;
31+
}
32+
33+
const errors = checkViolationsAndReturnErrors(input.responses, path);
34+
if (errors.length > 0) {
35+
return collectAndReturnViolation(path, RULE_NAME, errors);
36+
}
37+
38+
collectAdoption(path, RULE_NAME);
39+
};
40+
41+
/**
42+
* Check for violations in response structure
43+
*
44+
* @param {object} responses - The responses object to validate
45+
* @param {Array} path - Path to the responses in the document
46+
* @returns {Array} - Array of error objects
47+
*/
48+
function checkViolationsAndReturnErrors(responses, path) {
49+
try {
50+
if (!responses) {
51+
return [
52+
{
53+
path,
54+
message: ERROR_MESSAGE,
55+
},
56+
];
57+
}
58+
59+
// Check for 404 Not Found response
60+
if (!responses['404']) {
61+
return [
62+
{
63+
path,
64+
message: ERROR_MESSAGE,
65+
},
66+
];
67+
}
68+
69+
return [];
70+
} catch (e) {
71+
handleInternalError(RULE_NAME, path, e);
72+
}
73+
}

0 commit comments

Comments
 (0)