Skip to content

Commit eed1a14

Browse files
Merge branch 'main' into CLOUDP-304053
2 parents 5f28a92 + ee01c85 commit eed1a14

File tree

6 files changed

+350
-25
lines changed

6 files changed

+350
-25
lines changed
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
import testRule from './__helpers__/testRule';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
const componentSchemas = {
5+
schemas: {
6+
SchemaResponse: {
7+
type: 'object',
8+
},
9+
Schema: {
10+
type: 'object',
11+
},
12+
},
13+
};
14+
15+
testRule('xgen-IPA-104-get-method-returns-response-suffixed-object', [
16+
{
17+
name: 'valid schema names names',
18+
document: {
19+
paths: {
20+
'/resource/{id}': {
21+
get: {
22+
responses: {
23+
200: {
24+
content: {
25+
'application/vnd.atlas.2023-01-01+json': {
26+
schema: {
27+
$ref: '#/components/schemas/SchemaResponse',
28+
},
29+
},
30+
'application/vnd.atlas.2024-01-01+json': {
31+
schema: {
32+
$ref: '#/components/schemas/SchemaResponse',
33+
},
34+
},
35+
'application/vnd.atlas.2025-01-01+json': {
36+
schema: {
37+
type: 'array',
38+
items: {
39+
$ref: '#/components/schemas/SchemaResponse',
40+
},
41+
},
42+
},
43+
},
44+
},
45+
400: {
46+
content: {
47+
'application/vnd.atlas.2023-01-01+json': {
48+
schema: {
49+
$ref: '#/components/schemas/Schema',
50+
},
51+
},
52+
},
53+
},
54+
},
55+
},
56+
},
57+
'/resourceTwo/{id}': {
58+
get: {
59+
responses: {
60+
200: {
61+
content: {
62+
'application/vnd.atlas.2024-08-05+json': {
63+
type: 'string',
64+
},
65+
},
66+
},
67+
},
68+
},
69+
},
70+
'/resource/{id}/singleton': {
71+
get: {
72+
responses: {
73+
200: {
74+
content: {
75+
'application/vnd.atlas.2024-08-05+json': {
76+
schema: {
77+
$ref: '#/components/schemas/SchemaResponse',
78+
},
79+
},
80+
},
81+
},
82+
},
83+
},
84+
},
85+
},
86+
components: componentSchemas,
87+
},
88+
errors: [],
89+
},
90+
{
91+
name: 'invalid resources',
92+
document: {
93+
paths: {
94+
'/resource/{id}': {
95+
get: {
96+
responses: {
97+
200: {
98+
content: {
99+
'application/vnd.atlas.2023-01-01+json': {
100+
schema: {
101+
$ref: '#/components/schemas/Schema',
102+
},
103+
},
104+
'application/vnd.atlas.2024-01-01+json': {
105+
schema: {
106+
$ref: '#/components/schemas/Schema',
107+
},
108+
},
109+
'application/vnd.atlas.2025-01-01+json': {
110+
schema: {
111+
type: 'array',
112+
items: {
113+
$ref: '#/components/schemas/Schema',
114+
},
115+
},
116+
},
117+
},
118+
},
119+
},
120+
},
121+
},
122+
'/resource/{id}/singleton': {
123+
get: {
124+
responses: {
125+
200: {
126+
content: {
127+
'application/vnd.atlas.2024-08-05+json': {
128+
schema: {
129+
$ref: '#/components/schemas/Schema',
130+
},
131+
},
132+
},
133+
},
134+
},
135+
},
136+
},
137+
},
138+
components: componentSchemas,
139+
},
140+
errors: [
141+
{
142+
code: 'xgen-IPA-104-get-method-returns-response-suffixed-object',
143+
message: 'The request schema must reference a schema with a Response suffix. http://go/ipa/104',
144+
path: [
145+
'paths',
146+
'/resource/{id}',
147+
'get',
148+
'responses',
149+
'200',
150+
'content',
151+
'application/vnd.atlas.2023-01-01+json',
152+
],
153+
severity: DiagnosticSeverity.Warning,
154+
},
155+
{
156+
code: 'xgen-IPA-104-get-method-returns-response-suffixed-object',
157+
message: 'The request schema must reference a schema with a Response suffix. http://go/ipa/104',
158+
path: [
159+
'paths',
160+
'/resource/{id}',
161+
'get',
162+
'responses',
163+
'200',
164+
'content',
165+
'application/vnd.atlas.2024-01-01+json',
166+
],
167+
severity: DiagnosticSeverity.Warning,
168+
},
169+
{
170+
code: 'xgen-IPA-104-get-method-returns-response-suffixed-object',
171+
message: 'The request schema must reference a schema with a Response suffix. http://go/ipa/104',
172+
path: [
173+
'paths',
174+
'/resource/{id}',
175+
'get',
176+
'responses',
177+
'200',
178+
'content',
179+
'application/vnd.atlas.2025-01-01+json',
180+
],
181+
severity: DiagnosticSeverity.Warning,
182+
},
183+
{
184+
code: 'xgen-IPA-104-get-method-returns-response-suffixed-object',
185+
message: 'The request schema must reference a schema with a Response suffix. http://go/ipa/104',
186+
path: [
187+
'paths',
188+
'/resource/{id}/singleton',
189+
'get',
190+
'responses',
191+
'200',
192+
'content',
193+
'application/vnd.atlas.2024-08-05+json',
194+
],
195+
severity: DiagnosticSeverity.Warning,
196+
},
197+
],
198+
},
199+
{
200+
name: 'invalid resources with exceptions',
201+
document: {
202+
paths: {
203+
'/resource/{id}': {
204+
get: {
205+
responses: {
206+
200: {
207+
content: {
208+
'application/vnd.atlas.2023-01-01+json': {
209+
'x-xgen-IPA-exception': {
210+
'xgen-IPA-104-get-method-returns-response-suffixed-object': 'reason',
211+
},
212+
schema: {
213+
$ref: '#/components/schemas/Schema',
214+
},
215+
},
216+
'application/vnd.atlas.2024-01-01+json': {
217+
'x-xgen-IPA-exception': {
218+
'xgen-IPA-104-get-method-returns-response-suffixed-object': 'reason',
219+
},
220+
schema: {
221+
$ref: '#/components/schemas/Schema',
222+
},
223+
},
224+
'application/vnd.atlas.2025-01-01+json': {
225+
'x-xgen-IPA-exception': {
226+
'xgen-IPA-104-get-method-returns-response-suffixed-object': 'reason',
227+
},
228+
schema: {
229+
type: 'array',
230+
items: {
231+
$ref: '#/components/schemas/Schema',
232+
},
233+
},
234+
},
235+
},
236+
},
237+
},
238+
},
239+
},
240+
'/resource/{id}/singleton': {
241+
get: {
242+
responses: {
243+
200: {
244+
content: {
245+
'application/vnd.atlas.2024-08-05+json': {
246+
'x-xgen-IPA-exception': {
247+
'xgen-IPA-104-get-method-returns-response-suffixed-object': 'reason',
248+
},
249+
schema: {
250+
$ref: '#/components/schemas/Schema',
251+
},
252+
},
253+
},
254+
},
255+
},
256+
},
257+
},
258+
},
259+
components: componentSchemas,
260+
},
261+
errors: [],
262+
},
263+
]);

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@
44
functions:
55
- eachResourceHasGetMethod
66
- getMethodReturnsSingleResource
7+
- getMethodReturnsResponseSuffixedObject
78
- getResponseCodeShouldBe200OK
89

910
rules:
1011
xgen-IPA-104-resource-has-GET:
11-
description: 'APIs must provide a get method for resources. http://go/ipa/104'
12+
description: 'APIs must provide a Get method for resources. http://go/ipa/104'
1213
message: '{{error}} http://go/ipa/104'
1314
severity: warn
1415
given: '$.paths'
1516
then:
1617
field: '@key'
1718
function: 'eachResourceHasGetMethod'
1819
xgen-IPA-104-get-method-returns-single-resource:
19-
description: 'The purpose of the get method is to return data from a single resource. http://go/ipa/104'
20+
description: 'The purpose of the Get method is to return data from a single resource. http://go/ipa/104'
2021
message: '{{error}} http://go/ipa/104'
2122
severity: warn
2223
given: '$.paths[*].get'
@@ -29,3 +30,11 @@ rules:
2930
given: '$.paths[*].get'
3031
then:
3132
function: 'getResponseCodeShouldBe200OK'
33+
xgen-IPA-104-get-method-returns-response-suffixed-object:
34+
description: 'The Get method of a resource should return a "Response" suffixed object. http://go/ipa/104'
35+
message: '{{error}} http://go/ipa/104'
36+
severity: warn
37+
given: '$.paths[*].get.responses[*].content'
38+
then:
39+
field: '@key'
40+
function: 'getMethodReturnsResponseSuffixedObject'

tools/spectral/ipa/rulesets/README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ For rule definitions, see [IPA-102.yaml](https://github.com/mongodb/openapi/blob
2828

2929
For rule definitions, see [IPA-104.yaml](https://github.com/mongodb/openapi/blob/main/tools/spectral/ipa/rulesets/IPA-104.yaml).
3030

31-
| Rule Name | Description | Severity |
32-
| ----------------------------------------------- | ----------------------------------------------------------------------------------------- | -------- |
33-
| xgen-IPA-104-resource-has-GET | APIs must provide a get method for resources. http://go/ipa/104 | warn |
34-
| 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 |
35-
| xgen-IPA-104-get-method-response-code-is-200 | The Get method must return a 200 OK response. http://go/ipa/104 | warn |
31+
| Rule Name | Description | Severity |
32+
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------ | -------- |
33+
| xgen-IPA-104-resource-has-GET | APIs must provide a Get method for resources. http://go/ipa/104 | warn |
34+
| 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 |
35+
| xgen-IPA-104-get-method-response-code-is-200 | The Get method must return a 200 OK response. http://go/ipa/104 | warn |
36+
| 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 |
3637

3738
### IPA-106
3839

tools/spectral/ipa/rulesets/functions/createMethodRequestBodyIsRequestSuffixedObject.js

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { hasException } from './utils/exceptions.js';
22
import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js';
33
import { isCustomMethodIdentifier } from './utils/resourceEvaluation.js';
44
import { resolveObject } from './utils/componentUtils.js';
5+
import { getSchemaRef } from './utils/methodUtils.js';
56

67
const RULE_NAME = 'xgen-IPA-106-create-method-request-body-is-request-suffixed-object';
78
const ERROR_MESSAGE_SCHEMA_NAME = 'The response body schema must reference a schema with a Request suffix.';
@@ -10,8 +11,9 @@ const ERROR_MESSAGE_SCHEMA_REF = 'The response body schema is defined inline and
1011
export default (input, _, { path, documentInventory }) => {
1112
const oas = documentInventory.unresolved;
1213
const resourcePath = path[1];
14+
const contentMediaType = path[path.length - 1];
1315

14-
if (isCustomMethodIdentifier(resourcePath)) {
16+
if (isCustomMethodIdentifier(resourcePath) || !contentMediaType.endsWith('json')) {
1517
return;
1618
}
1719

@@ -24,24 +26,13 @@ export default (input, _, { path, documentInventory }) => {
2426

2527
if (contentPerMediaType.schema) {
2628
const schema = contentPerMediaType.schema;
27-
if (schema.type === 'array' && schema.items) {
28-
let schemaItems = schema.items;
29-
if (!schemaItems.$ref) {
30-
return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE_SCHEMA_REF);
31-
}
32-
if (!schemaItems.$ref.endsWith('Request')) {
33-
return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE_SCHEMA_NAME);
34-
}
35-
} else {
36-
if (!schema.$ref) {
37-
return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE_SCHEMA_REF);
38-
}
39-
40-
if (!schema.$ref.endsWith('Request')) {
41-
return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE_SCHEMA_NAME);
42-
}
29+
const schemaRef = getSchemaRef(schema);
30+
if (!schemaRef) {
31+
return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE_SCHEMA_REF);
32+
}
33+
if (!schemaRef.endsWith('Request')) {
34+
return collectAndReturnViolation(path, RULE_NAME, ERROR_MESSAGE_SCHEMA_NAME);
4335
}
44-
4536
collectAdoption(path, RULE_NAME);
4637
}
4738
};

0 commit comments

Comments
 (0)