Skip to content

Commit a260a2a

Browse files
CLOUDP-304055: IPA-106 Create: The request should be a Request suffixed object (#473)
1 parent 4fb74ff commit a260a2a

File tree

5 files changed

+282
-0
lines changed

5 files changed

+282
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
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+
'/resource2': {
97+
post: {
98+
requestBody: {
99+
content: {
100+
'application/vnd.atlas.2023-01-01+json': {
101+
schema: {
102+
$ref: '#/components/schemas/Schema',
103+
},
104+
},
105+
'application/vnd.atlas.2024-01-01+json': {
106+
schema: {
107+
$ref: '#/components/schemas/Schema',
108+
},
109+
},
110+
},
111+
},
112+
},
113+
},
114+
'/resource3': {
115+
post: {
116+
requestBody: {
117+
content: {
118+
'application/vnd.atlas.2023-01-01+json': {
119+
schema: {
120+
type: 'object',
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: 'The response body schema must reference a schema with a Request suffix. 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: 'The response body schema must reference a schema with a Request suffix. http://go/ipa/106',
139+
path: ['paths', '/resource2', '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: 'The response body schema must reference a schema with a Request suffix. http://go/ipa/106',
145+
path: ['paths', '/resource2', 'post', 'requestBody', 'content', 'application/vnd.atlas.2024-01-01+json'],
146+
severity: DiagnosticSeverity.Warning,
147+
},
148+
{
149+
code: 'xgen-IPA-106-create-method-request-body-is-request-suffixed-object',
150+
message: 'The response body schema is defined inline and must reference a predefined schema. http://go/ipa/106',
151+
path: ['paths', '/resource3', 'post', 'requestBody', 'content', 'application/vnd.atlas.2023-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+
'x-xgen-IPA-exception': {
170+
'xgen-IPA-106-create-method-request-body-is-request-suffixed-object': 'reason',
171+
},
172+
},
173+
},
174+
},
175+
},
176+
},
177+
'/resource2': {
178+
post: {
179+
requestBody: {
180+
content: {
181+
'application/vnd.atlas.2023-01-01+json': {
182+
schema: {
183+
$ref: '#/components/schemas/Schema',
184+
},
185+
'x-xgen-IPA-exception': {
186+
'xgen-IPA-106-create-method-request-body-is-request-suffixed-object': 'reason',
187+
},
188+
},
189+
'application/vnd.atlas.2024-01-01+json': {
190+
schema: {
191+
$ref: '#/components/schemas/Schema',
192+
},
193+
'x-xgen-IPA-exception': {
194+
'xgen-IPA-106-create-method-request-body-is-request-suffixed-object': 'reason',
195+
},
196+
},
197+
},
198+
},
199+
},
200+
},
201+
'/resource3': {
202+
post: {
203+
requestBody: {
204+
content: {
205+
'application/vnd.atlas.2023-01-01+json': {
206+
schema: {
207+
type: 'object',
208+
},
209+
'x-xgen-IPA-exception': {
210+
'xgen-IPA-106-create-method-request-body-is-request-suffixed-object': 'reason',
211+
},
212+
},
213+
},
214+
},
215+
},
216+
},
217+
},
218+
},
219+
errors: [],
220+
},
221+
]);

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: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
field: '@key'
15+
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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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_SCHEMA_NAME = 'The response body schema must reference a schema with a Request suffix.';
8+
const ERROR_MESSAGE_SCHEMA_REF = 'The response body schema is defined inline and must reference a predefined schema.';
9+
10+
export default (input, _, { path, documentInventory }) => {
11+
const oas = documentInventory.unresolved;
12+
const resourcePath = path[1];
13+
14+
if (isCustomMethod(resourcePath)) {
15+
return;
16+
}
17+
18+
const contentPerMediaType = resolveObject(oas, path);
19+
20+
if (hasException(contentPerMediaType, RULE_NAME)) {
21+
collectException(contentPerMediaType, RULE_NAME, path);
22+
return;
23+
}
24+
25+
if (contentPerMediaType.schema) {
26+
const schema = contentPerMediaType.schema;
27+
if (!schema.$ref) {
28+
return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE_SCHEMA_REF);
29+
}
30+
31+
if (!schema.$ref.endsWith('Request')) {
32+
return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE_SCHEMA_NAME);
33+
}
34+
}
35+
36+
collectAdoption(path, RULE_NAME);
37+
};

0 commit comments

Comments
 (0)