diff --git a/tools/spectral/ipa/__tests__/getMethodHasNoRequestBody.test.js b/tools/spectral/ipa/__tests__/getMethodHasNoRequestBody.test.js new file mode 100644 index 0000000000..63453fbc02 --- /dev/null +++ b/tools/spectral/ipa/__tests__/getMethodHasNoRequestBody.test.js @@ -0,0 +1,98 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-104-get-method-no-request-body', [ + { + name: 'valid GET without body', + document: { + paths: { + '/resource/{id}': { + get: { + responses: { + 200: {}, + }, + }, + }, + '/resource/{id}/singleton': { + get: { + responses: { + 200: {}, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid GET with body', + document: { + paths: { + '/resource/{id}': { + get: { + responses: { + 200: {}, + }, + requestBody: { + content: { + 'application/vnd.atlas.2024-08-05+json': { + schema: { type: 'object' }, + }, + }, + }, + }, + }, + '/resource/{id}/singleton': { + get: { + requestBody: { + content: { + 'application/vnd.atlas.2024-08-05+json': { + schema: { type: 'object' }, + }, + }, + }, + responses: { + 200: {}, + }, + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-104-get-method-no-request-body', + message: 'The Get method must not include a request body. http://go/ipa/104', + path: ['paths', '/resource/{id}', 'get'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-104-get-method-no-request-body', + message: 'The Get method must not include a request body. http://go/ipa/104', + path: ['paths', '/resource/{id}/singleton', 'get'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'invalid with exception', + document: { + paths: { + '/resource/{id}': { + get: { + 'x-xgen-IPA-exception': { + 'xgen-IPA-104-get-method-no-request-body': 'reason', + }, + requestBody: { + content: { + 'application/json': { + schema: { type: 'object' }, + }, + }, + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index dcf9e6461f..de4a4da8ad 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -6,6 +6,7 @@ functions: - getMethodReturnsSingleResource - getMethodReturnsResponseSuffixedObject - getResponseCodeShouldBe200OK + - getMethodHasNoRequestBody rules: xgen-IPA-104-resource-has-GET: @@ -38,3 +39,10 @@ rules: then: field: '@key' function: 'getMethodReturnsResponseSuffixedObject' + xgen-IPA-104-get-method-no-request-body: + description: 'The Get method request must not include a body. http://go/ipa/104' + message: '{{error}} http://go/ipa/104' + severity: warn + given: '$.paths[*].get' + then: + function: 'getMethodHasNoRequestBody' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 619ef6572b..29b1391d2d 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -34,6 +34,7 @@ For rule definitions, see [IPA-104.yaml](https://github.com/mongodb/openapi/blob | xgen-IPA-104-get-method-returns-single-resource | The purpose of the Get method is to return data from a single resource. http://go/ipa/104 | warn | | xgen-IPA-104-get-method-response-code-is-200 | The Get method must return a 200 OK response. http://go/ipa/104 | warn | | xgen-IPA-104-get-method-returns-response-suffixed-object | The Get method of a resource should return a "Response" suffixed object. http://go/ipa/104 | warn | +| xgen-IPA-104-get-method-no-request-body | The Get method request must not include a body. http://go/ipa/104 | warn | ### IPA-106 diff --git a/tools/spectral/ipa/rulesets/functions/getMethodHasNoRequestBody.js b/tools/spectral/ipa/rulesets/functions/getMethodHasNoRequestBody.js new file mode 100644 index 0000000000..fec316bd8b --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/getMethodHasNoRequestBody.js @@ -0,0 +1,44 @@ +import { hasException } from './utils/exceptions.js'; +import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; +import { + getResourcePathItems, + isResourceCollectionIdentifier, + isSingleResourceIdentifier, + isSingletonResource, +} from './utils/resourceEvaluation.js'; + +const RULE_NAME = 'xgen-IPA-104-get-method-no-request-body'; +const ERROR_MESSAGE = 'The Get method must not include a request body.'; + +export default (input, _, { path, documentInventory }) => { + const resourcePath = path[1]; + const oas = documentInventory.resolved; + + if ( + !isSingleResourceIdentifier(resourcePath) && + !( + isResourceCollectionIdentifier(resourcePath) && isSingletonResource(getResourcePathItems(resourcePath, oas.paths)) + ) + ) { + return; + } + + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); + return; + } + + const errors = checkViolationsAndReturnErrors(input, path); + + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(path, RULE_NAME); +}; + +function checkViolationsAndReturnErrors(getOperationObject, path) { + if (getOperationObject.requestBody) { + return [{ path, message: ERROR_MESSAGE }]; + } + return []; +}