Skip to content

Commit b884c72

Browse files
CLOUDP-304948: IPA 109: Custom Methods : The HTTP URI must use a colon(:) character followed by the custom method name
1 parent d658d5d commit b884c72

File tree

4 files changed

+211
-0
lines changed

4 files changed

+211
-0
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import testRule from './__helpers__/testRule';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
testRule('xgen-IPA-109-custom-method-identifier-format', [
5+
{
6+
name: 'valid custom method formats',
7+
document: {
8+
paths: {
9+
'/resource:customMethod': {},
10+
'/resource/{resourceId}:customMethod': {},
11+
'/resource/{resourceId}/subresource:customMethod': {},
12+
'/resource/{resourceId}/subresource/{resourceId}:customMethod': {},
13+
'/resource/subresource/{resourceId}:customMethod': {},
14+
'/resource/{resourceId}/subresource/{resourceId}/nested:customMethod': {},
15+
'/resource/{resourceId}/subresource/{resourceId}/nested/{resourceId}:customMethod': {},
16+
'/resource/subresource/nested/{resourceId}:customMethod': {},
17+
},
18+
},
19+
errors: [],
20+
},
21+
{
22+
name: 'invalid custom method formats not validated by this rule',
23+
document: {
24+
paths: {
25+
'/resources:custom&method': {},
26+
'/resources:custom/method': {},
27+
},
28+
},
29+
errors: [],
30+
},
31+
{
32+
name: 'invalid custom method with exception',
33+
document: {
34+
paths: {
35+
'/resources/:customMethod': {
36+
'x-xgen-IPA-exception': {
37+
'xgen-IPA-109-custom-method-identifier-format': 'exception reason',
38+
},
39+
},
40+
'/resources:{resourceId}:customMethod': {
41+
'x-xgen-IPA-exception': {
42+
'xgen-IPA-109-custom-method-identifier-format': 'exception reason',
43+
},
44+
},
45+
},
46+
},
47+
errors: [],
48+
},
49+
{
50+
name: 'invalid custom method formats',
51+
document: {
52+
paths: {
53+
'/resources/:customMethod': {},
54+
'/resources:{resourceId}:customMethod': {},
55+
'/resources/:{resourceId}:customMethod': {},
56+
'/:customMethod': {},
57+
'/resources/{resourceId}/:customMethod': {},
58+
'/resources/{resourceId}:custom::Method': {},
59+
},
60+
},
61+
errors: [
62+
{
63+
code: 'xgen-IPA-109-custom-method-identifier-format',
64+
message:
65+
"The path /resources/:customMethod contains a '/' before a custom method. Custom methods should not start with a '/'.",
66+
path: ['paths', '/resources/:customMethod'],
67+
severity: DiagnosticSeverity.Error,
68+
},
69+
{
70+
code: 'xgen-IPA-109-custom-method-identifier-format',
71+
message: 'Multiple colons found in "/resources:{resourceId}:customMethod"',
72+
path: ['paths', '/resources:{resourceId}:customMethod'],
73+
severity: DiagnosticSeverity.Error,
74+
},
75+
{
76+
code: 'xgen-IPA-109-custom-method-identifier-format',
77+
message: 'Multiple colons found in "/resources/:{resourceId}:customMethod".',
78+
path: ['paths', '/resources/:{resourceId}:customMethod'],
79+
severity: DiagnosticSeverity.Error,
80+
},
81+
{
82+
code: 'xgen-IPA-109-custom-method-identifier-format',
83+
message:
84+
"The path /:customMethod contains a '/' before a custom method. Custom methods should not start with a '/'.",
85+
path: ['paths', '/:customMethod'],
86+
severity: DiagnosticSeverity.Error,
87+
},
88+
{
89+
code: 'xgen-IPA-109-custom-method-identifier-format',
90+
message:
91+
"The path /resources/{resourceId}/:customMethod contains a \'/\' before a custom method. Custom methods should not start with a \'/\'.",
92+
path: ['paths', '/resources/{resourceId}/:customMethod'],
93+
severity: DiagnosticSeverity.Error,
94+
},
95+
{
96+
code: 'xgen-IPA-109-custom-method-identifier-format',
97+
message: 'Multiple colons found in "/resources/{resourceId}:custom::Method".',
98+
path: ['paths', '/resources/{resourceId}:custom::Method'],
99+
severity: DiagnosticSeverity.Error,
100+
},
101+
],
102+
},
103+
]);

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
functions:
55
- IPA109EachCustomMethodMustBeGetOrPost
66
- IPA109EachCustomMethodMustUseCamelCase
7+
- IPA109CustomMethodIdentifierFormat
78

89
rules:
910
xgen-IPA-109-custom-method-must-be-GET-or-POST:
@@ -38,3 +39,20 @@ rules:
3839
given: '$.paths[*]'
3940
then:
4041
function: 'IPA109EachCustomMethodMustUseCamelCase'
42+
xgen-IPA-109-custom-method-identifier-format:
43+
description: |
44+
Custom methods must be defined using a colon followed by the method name.
45+
46+
##### Implementation details
47+
Rule checks for the following conditions:
48+
- Identifies paths containing a colon (potential custom methods)
49+
- Validates that the path follows proper custom method format
50+
- Does not validate after the colon (xgen-IPA-109-custom-method-must-use-camel-case rule validates the method name)
51+
- Fails if a slash appears before a colon
52+
- Fails if multiple colons appear in the path
53+
- Fails if other than an alphabetical character or a closing curly brace appears before a colon
54+
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-109-custom-method-identifier-format'
55+
severity: error
56+
given: '$.paths[*]'
57+
then:
58+
function: 'IPA109CustomMethodIdentifierFormat'

tools/spectral/ipa/rulesets/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,20 @@ Rule checks for the following conditions:
396396
- Validates that the method name uses proper camelCase formatting
397397
- Fails if the method name contains invalid casing (such as snake_case, PascalCase, etc.)
398398

399+
#### xgen-IPA-109-custom-method-identifier-format
400+
401+
![error](https://img.shields.io/badge/error-red)
402+
Custom methods must be defined using a colon followed by the method name.
403+
404+
##### Implementation details
405+
Rule checks for the following conditions:
406+
- Identifies paths containing a colon (potential custom methods)
407+
- Validates that the path follows proper custom method format
408+
- Does not validate after the colon (xgen-IPA-109-custom-method-must-use-camel-case rule validates the method name)
409+
- Fails if a slash appears before a colon
410+
- Fails if multiple colons appear in the path
411+
- Fails if other than an alphabetical character or a closing curly brace appears before a colon
412+
399413

400414

401415
### IPA-113
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import {
2+
collectAdoption,
3+
collectAndReturnViolation,
4+
collectException,
5+
handleInternalError,
6+
} from './utils/collectionUtils.js';
7+
import { isCustomMethodIdentifier } from './utils/resourceEvaluation.js';
8+
import { hasException } from './utils/exceptions.js';
9+
10+
const RULE_NAME = 'xgen-IPA-109-custom-method-identifier-format';
11+
12+
/**
13+
* Validates custom method identifiers follow the correct format pattern.
14+
* Custom methods should be defined using a colon character followed by the method name.
15+
* Valid formats: /resources/{resourceId}:customMethod or /resources:customMethod
16+
*
17+
* @param {object} input - The path string being evaluated
18+
* @param {object} _ - Unused
19+
* @param {object} context - The context object containing path and document information
20+
*/
21+
export default (input, _, { path }) => {
22+
let pathKey = path[1];
23+
24+
if (!isCustomMethodIdentifier(pathKey)) {
25+
return;
26+
}
27+
28+
if (hasException(input, RULE_NAME)) {
29+
collectException(input, RULE_NAME, path);
30+
return;
31+
}
32+
33+
const errors = checkViolationsAndReturnErrors(pathKey, path);
34+
if (errors.length !== 0) {
35+
return collectAndReturnViolation(path, RULE_NAME, errors);
36+
}
37+
collectAdoption(path, RULE_NAME);
38+
};
39+
40+
function checkViolationsAndReturnErrors(pathKey, path) {
41+
try {
42+
// Check for multiple colons
43+
const colonCount = (pathKey.match(/:/g) || []).length;
44+
if (colonCount > 1) {
45+
return [{ path, message: `Multiple colons found in "${pathKey}".` }];
46+
}
47+
48+
// Check for slash before colon
49+
const invalidSlashBeforeColonPattern = /\/:/;
50+
51+
if (invalidSlashBeforeColonPattern.test(pathKey)) {
52+
return [
53+
{
54+
path,
55+
message: `The path ${pathKey} contains a '/' before a custom method. Custom methods should not start with a '/'.`,
56+
},
57+
];
58+
}
59+
60+
// Check for invalid character before colon
61+
// The character before colon should be either an alphabetical character or a closing curly brace '}'
62+
const beforeColonMatch = pathKey.match(/([^a-zA-Z}]):/);
63+
if (beforeColonMatch && beforeColonMatch[1] !== '') {
64+
return [
65+
{
66+
path,
67+
message: `Invalid character '${beforeColonMatch[1]}' before colon in "${pathKey}".`,
68+
},
69+
];
70+
}
71+
72+
return [];
73+
} catch (e) {
74+
handleInternalError(RULE_NAME, path, e);
75+
}
76+
}

0 commit comments

Comments
 (0)