Skip to content
Merged
122 changes: 122 additions & 0 deletions tools/spectral/ipa/__tests__/eachCustomMethodMustBeGetOrPost.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

testRule('xgen-IPA-109-custom-method-must-be-GET-or-POST', [
{
name: 'valid methods',
document: {
paths: {
'/a/{exampleId}:method': {
post: {},
},
'/a:method': {
post: {},
},
'/b/{exampleId}:method': {
get: {},
},
'/b:method': {
get: {},
},
'/c/{exampleId}:method': {
get: {},
'x-xgen-IPA-exception': {},
},
'/c:method': {
get: {},
'x-xgen-IPA-exception': {},
},
},
},
errors: [],
},
{
name: 'invalid methods',
document: {
paths: {
'/a/{exampleId}:method': {
put: {},
},
'/a:method': {
put: {},
},
'/b/{exampleId}:method': {
get: {},
put: {},
},
'/b:method': {
get: {},
put: {},
},
'/c/{exampleId}:method': {
post: {},
get: {},
put: {},
},
'/c:method': {
post: {},
get: {},
put: {},
},
'/d/{exampleId}:method': {
post: {},
get: {},
},
'/d:method': {
post: {},
get: {},
},
},
},
errors: [
{
code: 'xgen-IPA-109-custom-method-must-be-GET-or-POST',
message: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109',
path: ['paths', '/a/{exampleId}:method'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-109-custom-method-must-be-GET-or-POST',
message: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109',
path: ['paths', '/a:method'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-109-custom-method-must-be-GET-or-POST',
message: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109',
path: ['paths', '/b/{exampleId}:method'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-109-custom-method-must-be-GET-or-POST',
message: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109',
path: ['paths', '/b:method'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-109-custom-method-must-be-GET-or-POST',
message: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109',
path: ['paths', '/c/{exampleId}:method'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-109-custom-method-must-be-GET-or-POST',
message: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109',
path: ['paths', '/c:method'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-109-custom-method-must-be-GET-or-POST',
message: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109',
path: ['paths', '/d/{exampleId}:method'],
severity: DiagnosticSeverity.Warning,
},
{
code: 'xgen-IPA-109-custom-method-must-be-GET-or-POST',
message: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109',
path: ['paths', '/d:method'],
severity: DiagnosticSeverity.Warning,
},
],
},
]);
3 changes: 2 additions & 1 deletion tools/spectral/ipa/ipa-spectral.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
extends:
- ./rulesets/IPA-005.yaml
- ./rulesets/IPA-102.yaml
- ./rulesets/IPA-104.yaml
- ./rulesets/IPA-005.yaml
- ./rulesets/IPA-109.yaml
14 changes: 14 additions & 0 deletions tools/spectral/ipa/rulesets/IPA-109.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# IPA-109: Custom Methods
# http://go/ipa/109

functions:
- eachCustomMethodMustBeGetOrPost

rules:
xgen-IPA-109-custom-method-must-be-GET-or-POST:
description: 'The HTTP method for custom methods must be GET or POST. http://go/ipa/109'
message: '{{error}} http://go/ipa/109'
severity: warn
given: '$.paths[*]'
then:
function: 'eachCustomMethodMustBeGetOrPost'
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { isCustomMethod } from './utils/resourceEvaluation.js';

const ERROR_MESSAGE = 'The HTTP method for custom methods must be GET or POST.';
const ERROR_RESULT = [{ message: ERROR_MESSAGE }];
const VALID_METHODS = ['get', 'post'];
const HTTP_METHODS = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Just a note for future rules]: I expect we will have other similar rules coming up, at that point we can consider refactoring out a common method to check for valid/invalid methods to the utils package


export default (input, opts, { path }) => {
// Extract the path key (e.g., '/a/{exampleId}:method') from the JSONPath.
let pathKey = path[1];

if (!isCustomMethod(pathKey)) return;

//Extract the keys which are equivalent of the http methods
let keys = Object.keys(input);
const httpMethods = keys.filter((key) => HTTP_METHODS.includes(key));

// Check for invalid methods
if (httpMethods.some((method) => !VALID_METHODS.includes(method))) {
return ERROR_RESULT;
}
Comment on lines +19 to +21
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this return error if the path has an exception extension?

Suggestion: use $.path[get,put,post,delete,options,head,patch,trace] to ignore any other objects than the methods, kinda like we do here:

- "#PathItem[get,put,post,delete,options,head,patch,trace]"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it would return error with an exception extension. Good catch!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"#PathItem[get,put,post,delete,options,head,patch,trace]" gives the object inside HTTP method. I will exclude x-xgen-IPA-exception


// Check for multiple valid methods
const validMethodCount = httpMethods.filter((method) => VALID_METHODS.includes(method)).length;

if (validMethodCount > 1) {
return ERROR_RESULT;
}
};
Loading