diff --git a/tools/spectral/ipa/__tests__/getResponseCodeShouldBe200OK.test.js b/tools/spectral/ipa/__tests__/getResponseCodeShouldBe200OK.test.js new file mode 100644 index 0000000000..4d26b4109b --- /dev/null +++ b/tools/spectral/ipa/__tests__/getResponseCodeShouldBe200OK.test.js @@ -0,0 +1,139 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-104-get-method-response-code-is-200', [ + { + name: 'valid methods', + document: { + paths: { + '/resource': { + get: { + responses: { + 400: {}, + 500: {}, + }, + }, + }, + '/resource/{id}': { + get: { + responses: { + 200: {}, + 400: {}, + 500: {}, + }, + }, + }, + '/resource/{id}:customMethod': { + get: { + responses: { + 400: {}, + 500: {}, + }, + }, + }, + '/singleton': { + get: { + responses: { + 400: {}, + 500: {}, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid methods', + document: { + paths: { + '/resource1': { get: { responses: {} } }, + '/resource1/{id}': { + get: { + responses: { + 201: {}, + 400: {}, + 500: {}, + }, + }, + }, + '/resource2': { get: { responses: {} } }, + '/resource2/{id}': { + get: { + responses: { + 400: {}, + 500: {}, + }, + }, + }, + '/resource3': { get: { responses: {} } }, + '/resource3/{id}': { + get: { + responses: { + 200: {}, + 201: {}, + 400: {}, + 500: {}, + }, + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-104-get-method-response-code-is-200', + message: + 'The Get method must return a 200 OK response. This method either lacks a 200 OK response or defines a different 2xx status code. http://go/ipa/104', + path: ['paths', '/resource1/{id}', 'get'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-104-get-method-response-code-is-200', + message: + 'The Get method must return a 200 OK response. This method either lacks a 200 OK response or defines a different 2xx status code. http://go/ipa/104', + path: ['paths', '/resource2/{id}', 'get'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-104-get-method-response-code-is-200', + message: + 'The Get method must return a 200 OK response. This method either lacks a 200 OK response or defines a different 2xx status code. http://go/ipa/104', + path: ['paths', '/resource3/{id}', 'get'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'invalid method with exception', + document: { + paths: { + '/resource1': { get: { responses: {} } }, + '/resource1/{id}': { + get: { + responses: { + 201: {}, + 400: {}, + 500: {}, + }, + 'x-xgen-IPA-exception': { + 'xgen-IPA-104-get-method-response-code-is-200': 'reason', + }, + }, + }, + '/resource2': { get: { responses: {} } }, + '/resource2/{id}': { + get: { + responses: { + 400: {}, + 500: {}, + }, + 'x-xgen-IPA-exception': { + 'xgen-IPA-104-get-method-response-code-is-200': 'reason', + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-104.yaml b/tools/spectral/ipa/rulesets/IPA-104.yaml index 5dc44a952a..da80f33d11 100644 --- a/tools/spectral/ipa/rulesets/IPA-104.yaml +++ b/tools/spectral/ipa/rulesets/IPA-104.yaml @@ -4,6 +4,7 @@ functions: - eachResourceHasGetMethod - getMethodReturnsSingleResource + - getResponseCodeShouldBe200OK rules: xgen-IPA-104-resource-has-GET: @@ -21,3 +22,11 @@ rules: given: '$.paths[*].get' then: function: 'getMethodReturnsSingleResource' + + xgen-IPA-104-get-method-response-code-is-200: + description: 'The Get method must return a 200 OK response. http://go/ipa/104' + message: '{{error}} http://go/ipa/104' + severity: warn + given: '$.paths[*].get' + then: + function: 'getResponseCodeShouldBe200OK' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 614b2fa8ef..db001ccf4f 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -32,6 +32,7 @@ For rule definitions, see [IPA-104.yaml](https://github.com/mongodb/openapi/blob | ----------------------------------------------- | ----------------------------------------------------------------------------------------- | -------- | | xgen-IPA-104-resource-has-GET | APIs must provide a get method for resources. http://go/ipa/104 | warn | | 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 | ### IPA-109 diff --git a/tools/spectral/ipa/rulesets/functions/getResponseCodeShouldBe200OK.js b/tools/spectral/ipa/rulesets/functions/getResponseCodeShouldBe200OK.js new file mode 100644 index 0000000000..aab6a0ff8f --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/getResponseCodeShouldBe200OK.js @@ -0,0 +1,36 @@ +import { hasException } from './utils/exceptions.js'; +import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; +import { isChild, isCustomMethod } from './utils/resourceEvaluation.js'; + +const RULE_NAME = 'xgen-IPA-104-get-method-response-code-is-200'; +const ERROR_MESSAGE = + 'The Get method must return a 200 OK response. This method either lacks a 200 OK response or defines a different 2xx status code.'; + +export default (input, _, { path }) => { + const resourcePath = path[1]; + + if (isCustomMethod(resourcePath) || !isChild(resourcePath)) { + return; + } + + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); + return; + } + + if (input['responses']) { + const responses = input['responses']; + + // If there is no 200 response, return a violation + if (!responses['200']) { + return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE); + } + + // If there are other 2xx responses that are not 200, return a violation + if (Object.keys(responses).some((key) => key.startsWith('2') && key !== '200')) { + return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE); + } + } + + collectAdoption(path, RULE_NAME); +};