Skip to content

Commit 5dec957

Browse files
IPA 106: Create : The response status code must be 201 Created (#527)
1 parent 7c4229d commit 5dec957

File tree

4 files changed

+185
-0
lines changed

4 files changed

+185
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import testRule from './__helpers__/testRule';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
testRule('xgen-IPA-106-create-method-response-code-is-201', [
5+
{
6+
name: 'valid methods',
7+
document: {
8+
paths: {
9+
'/resource': {
10+
post: {
11+
responses: {
12+
201: {},
13+
400: {},
14+
500: {},
15+
},
16+
},
17+
},
18+
'/resource/{id}/subresource': {
19+
post: {
20+
responses: {
21+
201: {},
22+
400: {},
23+
500: {},
24+
},
25+
},
26+
},
27+
'/resource/{id}:customMethod': {
28+
post: {
29+
responses: {
30+
200: {},
31+
400: {},
32+
500: {},
33+
},
34+
},
35+
},
36+
},
37+
},
38+
errors: [],
39+
},
40+
{
41+
name: 'invalid methods',
42+
document: {
43+
paths: {
44+
'/resourceOne': {
45+
post: {
46+
responses: {
47+
200: {},
48+
400: {},
49+
500: {},
50+
},
51+
},
52+
},
53+
'/resourceTwo': {
54+
post: {
55+
responses: {
56+
400: {},
57+
500: {},
58+
},
59+
},
60+
},
61+
'/resourceThree': {
62+
post: {
63+
responses: {
64+
201: {},
65+
200: {},
66+
400: {},
67+
500: {},
68+
},
69+
},
70+
},
71+
},
72+
},
73+
errors: [
74+
{
75+
code: 'xgen-IPA-106-create-method-response-code-is-201',
76+
message:
77+
'The Create method must return a 201 Created response. This method either lacks a 201 Created response or defines a different 2xx status code. http://go/ipa/106',
78+
path: ['paths', '/resourceOne', 'post'],
79+
severity: DiagnosticSeverity.Warning,
80+
},
81+
{
82+
code: 'xgen-IPA-106-create-method-response-code-is-201',
83+
message:
84+
'The Create method must return a 201 Created response. This method either lacks a 201 Created response or defines a different 2xx status code. http://go/ipa/106',
85+
path: ['paths', '/resourceTwo', 'post'],
86+
severity: DiagnosticSeverity.Warning,
87+
},
88+
{
89+
code: 'xgen-IPA-106-create-method-response-code-is-201',
90+
message:
91+
'The Create method must return a 201 Created response. This method either lacks a 201 Created response or defines a different 2xx status code. http://go/ipa/106',
92+
path: ['paths', '/resourceThree', 'post'],
93+
severity: DiagnosticSeverity.Warning,
94+
},
95+
],
96+
},
97+
{
98+
name: 'invalid method with exception',
99+
document: {
100+
paths: {
101+
'/resourceOne': {
102+
post: {
103+
responses: {
104+
200: {},
105+
400: {},
106+
500: {},
107+
},
108+
'x-xgen-IPA-exception': {
109+
'xgen-IPA-106-create-method-response-code-is-201': 'Reason',
110+
},
111+
},
112+
},
113+
},
114+
},
115+
errors: [],
116+
},
117+
]);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ functions:
66
- createMethodShouldNotHaveQueryParameters
77
- createMethodRequestBodyIsGetResponse
88
- createMethodRequestHasNoReadonlyFields
9+
- createMethodResponseCodeIs201Created
910

1011
rules:
1112
xgen-IPA-106-create-method-request-body-is-request-suffixed-object:
@@ -43,3 +44,10 @@ rules:
4344
then:
4445
field: '@key'
4546
function: 'createMethodRequestHasNoReadonlyFields'
47+
xgen-IPA-106-create-method-response-code-is-201:
48+
description: 'Create methods must return a 201 Created response code. http://go/ipa/106'
49+
message: '{{error}} http://go/ipa/106'
50+
severity: warn
51+
given: '$.paths[*].post'
52+
then:
53+
function: 'createMethodResponseCodeIs201Created'

tools/spectral/ipa/rulesets/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ For rule definitions, see [IPA-106.yaml](https://github.com/mongodb/openapi/blob
6161
readOnly/writeOnly properties will be ignored. http://go/ipa/106
6262
| warn |
6363
| xgen-IPA-106-create-method-request-has-no-readonly-fields | Create method Request object must not include fields with readOnly:true. http://go/ipa/106 | warn |
64+
| xgen-IPA-106-create-method-response-code-is-201 | Create methods must return a 201 Created response code. http://go/ipa/106 | warn |
6465

6566
### IPA-108
6667

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import {
2+
getResourcePathItems,
3+
isCustomMethodIdentifier,
4+
isResourceCollectionIdentifier,
5+
isSingletonResource,
6+
} from './utils/resourceEvaluation.js';
7+
import { hasException } from './utils/exceptions.js';
8+
import {
9+
collectAdoption,
10+
collectAndReturnViolation,
11+
collectException,
12+
handleInternalError,
13+
} from './utils/collectionUtils.js';
14+
15+
const RULE_NAME = 'xgen-IPA-106-create-method-response-code-is-201';
16+
const ERROR_MESSAGE =
17+
'The Create method must return a 201 Created response. This method either lacks a 201 Created response or defines a different 2xx status code.';
18+
19+
export default (input, _, { path, documentInventory }) => {
20+
const oas = documentInventory.resolved;
21+
const resourcePath = path[1];
22+
const resourcePaths = getResourcePathItems(resourcePath, oas.paths);
23+
24+
const isResourceCollection = isResourceCollectionIdentifier(resourcePath) && !isSingletonResource(resourcePaths);
25+
if (isCustomMethodIdentifier(resourcePath) || !isResourceCollection) {
26+
return;
27+
}
28+
29+
if (hasException(input, RULE_NAME)) {
30+
collectException(input, RULE_NAME, path);
31+
return;
32+
}
33+
34+
const errors = checkViolationsAndReturnErrors(input, path);
35+
if (errors.length !== 0) {
36+
return collectAndReturnViolation(path, RULE_NAME, errors);
37+
}
38+
collectAdoption(path, RULE_NAME);
39+
};
40+
41+
function checkViolationsAndReturnErrors(input, path) {
42+
try {
43+
const responses = input.responses;
44+
45+
// If there is no 201 response, return a violation
46+
if (!responses || !responses['201']) {
47+
return [{ path, message: ERROR_MESSAGE }];
48+
}
49+
50+
// If there are other 2xx responses that are not 201, return a violation
51+
if (Object.keys(responses).some((key) => key.startsWith('2') && key !== '201')) {
52+
return [{ path, message: ERROR_MESSAGE }];
53+
}
54+
55+
return [];
56+
} catch (e) {
57+
handleInternalError(RULE_NAME, path, e);
58+
}
59+
}

0 commit comments

Comments
 (0)