Skip to content

Commit bc9e113

Browse files
CLOUDP-304055: IPA-106 Create: The request should be a Request suffixed object
1 parent e64b541 commit bc9e113

File tree

5 files changed

+245
-0
lines changed

5 files changed

+245
-0
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import testRule from './__helpers__/testRule';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
const componentSchemas = {
5+
schemas: {
6+
SchemaRequest: {
7+
type: 'object',
8+
},
9+
Schema: {
10+
type: 'object',
11+
},
12+
},
13+
};
14+
testRule('xgen-IPA-106-create-method-request-body-is-request-suffixed-object', [
15+
{
16+
name: 'valid methods',
17+
document: {
18+
components: componentSchemas,
19+
paths: {
20+
'/resource': {
21+
post: {
22+
requestBody: {
23+
content: {
24+
'application/vnd.atlas.2023-01-01+json': {
25+
schema: {
26+
$ref: '#/components/schemas/SchemaRequest',
27+
},
28+
},
29+
'application/vnd.atlas.2024-01-01+json': {
30+
schema: {
31+
$ref: '#/components/schemas/SchemaRequest',
32+
},
33+
},
34+
},
35+
},
36+
},
37+
},
38+
'/resource/{id}': {
39+
post: {
40+
requestBody: {
41+
content: {
42+
'application/vnd.atlas.2023-01-01+json': {
43+
schema: {
44+
$ref: '#/components/schemas/SchemaRequest',
45+
},
46+
},
47+
'application/vnd.atlas.2024-01-01+json': {
48+
schema: {
49+
$ref: '#/components/schemas/SchemaRequest',
50+
},
51+
},
52+
},
53+
},
54+
},
55+
},
56+
'/resource/{id}:customMethod': {
57+
post: {
58+
requestBody: {
59+
content: {
60+
'application/vnd.atlas.2023-01-01+json': {
61+
schema: {
62+
$ref: '#/components/schemas/Schema',
63+
},
64+
},
65+
'application/vnd.atlas.2024-01-01+json': {
66+
schema: {
67+
$ref: '#/components/schemas/SchemaRequest',
68+
},
69+
},
70+
},
71+
},
72+
},
73+
},
74+
},
75+
},
76+
errors: [],
77+
},
78+
{
79+
name: 'invalid methods',
80+
document: {
81+
components: componentSchemas,
82+
paths: {
83+
'/resource': {
84+
post: {
85+
requestBody: {
86+
content: {
87+
'application/vnd.atlas.2023-01-01+json': {
88+
schema: {
89+
$ref: '#/components/schemas/Schema',
90+
},
91+
},
92+
},
93+
},
94+
},
95+
},
96+
'/resource/{id}': {
97+
post: {
98+
requestBody: {
99+
content: {
100+
'application/vnd.atlas.2023-01-01+json': {
101+
schema: {
102+
$ref: '#/components/schemas/Schema',
103+
},
104+
},
105+
},
106+
},
107+
},
108+
},
109+
'/resource2': {
110+
post: {
111+
requestBody: {
112+
content: {
113+
'application/vnd.atlas.2023-01-01+json': {
114+
schema: {
115+
$ref: '#/components/schemas/Schema',
116+
},
117+
},
118+
'application/vnd.atlas.2024-01-01+json': {
119+
schema: {
120+
$ref: '#/components/schemas/Schema',
121+
},
122+
},
123+
},
124+
},
125+
},
126+
},
127+
},
128+
},
129+
errors: [
130+
{
131+
code: 'xgen-IPA-106-create-method-request-body-is-request-suffixed-object',
132+
message: 'Response body for the Create method should refer to Request suffixed schema. http://go/ipa/106',
133+
path: ['paths', '/resource', 'post', 'requestBody', 'content', 'application/vnd.atlas.2023-01-01+json'],
134+
severity: DiagnosticSeverity.Warning,
135+
},
136+
{
137+
code: 'xgen-IPA-106-create-method-request-body-is-request-suffixed-object',
138+
message: 'Response body for the Create method should refer to Request suffixed schema. http://go/ipa/106',
139+
path: ['paths', '/resource/{id}', 'post', 'requestBody', 'content', 'application/vnd.atlas.2023-01-01+json'],
140+
severity: DiagnosticSeverity.Warning,
141+
},
142+
{
143+
code: 'xgen-IPA-106-create-method-request-body-is-request-suffixed-object',
144+
message: 'Response body for the Create method should refer to Request suffixed schema. http://go/ipa/106',
145+
path: ['paths', '/resource2', 'post', 'requestBody', 'content', 'application/vnd.atlas.2023-01-01+json'],
146+
severity: DiagnosticSeverity.Warning,
147+
},
148+
{
149+
code: 'xgen-IPA-106-create-method-request-body-is-request-suffixed-object',
150+
message: 'Response body for the Create method should refer to Request suffixed schema. http://go/ipa/106',
151+
path: ['paths', '/resource2', 'post', 'requestBody', 'content', 'application/vnd.atlas.2024-01-01+json'],
152+
severity: DiagnosticSeverity.Warning,
153+
},
154+
],
155+
},
156+
{
157+
name: 'invalid method with exception',
158+
document: {
159+
components: componentSchemas,
160+
paths: {
161+
'/resource': {
162+
post: {
163+
requestBody: {
164+
content: {
165+
'application/vnd.atlas.2023-01-01+json': {
166+
schema: {
167+
$ref: '#/components/schemas/Schema',
168+
},
169+
},
170+
'x-xgen-IPA-exception': {
171+
'xgen-IPA-106-create-method-request-body-is-request-suffixed-object': 'reason',
172+
},
173+
},
174+
},
175+
},
176+
},
177+
},
178+
},
179+
errors: [],
180+
},
181+
]);

tools/spectral/ipa/ipa-spectral.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ extends:
55
- ./rulesets/IPA-109.yaml
66
- ./rulesets/IPA-113.yaml
77
- ./rulesets/IPA-123.yaml
8+
- ./rulesets/IPA-106.yaml
89

910
overrides:
1011
- files:
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# IPA-104: Create
2+
# http://go/ipa/106
3+
4+
functions:
5+
- createMethodRequestBodyIsRequestSuffixedObject
6+
7+
rules:
8+
xgen-IPA-106-create-method-request-body-is-request-suffixed-object:
9+
description: 'The Create method request should be a Request suffixed object. http://go/ipa/106'
10+
message: '{{error}} http://go/ipa/106'
11+
severity: warn
12+
given: '$.paths[*].post.requestBody.content'
13+
then:
14+
function: 'createMethodRequestBodyIsRequestSuffixedObject'

tools/spectral/ipa/rulesets/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ For rule definitions, see [IPA-104.yaml](https://github.com/mongodb/openapi/blob
3434
| 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 |
3535
| xgen-IPA-104-get-method-response-code-is-200 | The Get method must return a 200 OK response. http://go/ipa/104 | warn |
3636

37+
### IPA-106
38+
39+
For rule definitions, see [IPA-106.yaml](https://github.com/mongodb/openapi/blob/main/tools/spectral/ipa/rulesets/IPA-106.yaml).
40+
41+
| Rule Name | Description | Severity |
42+
| ------------------------------------------------------------------ | -------------------------------------------------------------------------------- | -------- |
43+
| xgen-IPA-106-create-method-request-body-is-request-suffixed-object | The Create method request should be a Request suffixed object. http://go/ipa/106 | warn |
44+
3745
### IPA-109
3846

3947
For rule definitions, see [IPA-109.yaml](https://github.com/mongodb/openapi/blob/main/tools/spectral/ipa/rulesets/IPA-109.yaml).
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { hasException } from './utils/exceptions.js';
2+
import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js';
3+
import { isCustomMethod } from './utils/resourceEvaluation.js';
4+
import { resolveObject } from './utils/componentUtils.js';
5+
6+
const RULE_NAME = 'xgen-IPA-106-create-method-request-body-is-request-suffixed-object';
7+
const ERROR_MESSAGE = 'Response body for the Create method should refer to Request suffixed schema.';
8+
9+
export default (input, _, { path, documentInventory }) => {
10+
const oas = documentInventory.unresolved;
11+
const resourcePath = path[1];
12+
if (isCustomMethod(resourcePath)) {
13+
return;
14+
}
15+
16+
const content = resolveObject(oas, path);
17+
if (hasException(content, RULE_NAME)) {
18+
collectException(content, RULE_NAME, path);
19+
return;
20+
}
21+
22+
const errors = [];
23+
for (const mediaType in content) {
24+
const media = content[mediaType];
25+
if (media.schema) {
26+
const schema = media.schema;
27+
if (schema.$ref && !schema.$ref.endsWith('Request')) {
28+
errors.push({
29+
path: path.concat(mediaType),
30+
message: `${ERROR_MESSAGE}`,
31+
});
32+
}
33+
}
34+
}
35+
36+
if (errors.length === 0) {
37+
collectAdoption(path, RULE_NAME);
38+
} else {
39+
return collectAndReturnViolation(path, RULE_NAME, errors);
40+
}
41+
};

0 commit comments

Comments
 (0)