Skip to content

Commit 331eea2

Browse files
CLOUDP-304961: IPA-114: Errors (ApiError schema properties)
1 parent 281b54c commit 331eea2

File tree

4 files changed

+264
-0
lines changed

4 files changed

+264
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import testRule from './__helpers__/testRule';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
const validDocument = {
5+
components: {
6+
schemas: {
7+
ApiError: {
8+
properties: {
9+
badRequestDetail: {
10+
$ref: '#/components/schemas/BadRequestDetail',
11+
},
12+
detail: { type: 'string' },
13+
},
14+
},
15+
BadRequestDetail: {
16+
properties: {
17+
fields: {
18+
type: 'array',
19+
items: {
20+
$ref: '#/components/schemas/FieldViolation',
21+
},
22+
},
23+
},
24+
},
25+
FieldViolation: {
26+
properties: {
27+
description: { type: 'string' },
28+
field: { type: 'string' },
29+
},
30+
required: ['description', 'field'],
31+
},
32+
},
33+
},
34+
};
35+
36+
testRule('xgen-IPA-114-api-error-has-bad-request-detail', [
37+
{
38+
name: 'valid ApiError schema passes validation',
39+
document: validDocument,
40+
errors: [],
41+
},
42+
{
43+
name: 'missing properties in ApiError fails',
44+
document: {
45+
components: {
46+
schemas: {
47+
ApiError: {},
48+
},
49+
},
50+
},
51+
errors: [
52+
{
53+
code: 'xgen-IPA-114-api-error-has-bad-request-detail',
54+
message: 'ApiError schema must have badRequestDetail field.',
55+
path: ['components', 'schemas', 'ApiError'],
56+
severity: DiagnosticSeverity.Warning,
57+
},
58+
],
59+
},
60+
{
61+
name: 'missing badRequestDetail field fails',
62+
document: {
63+
components: {
64+
schemas: {
65+
ApiError: {
66+
properties: {
67+
detail: { type: 'string' },
68+
},
69+
},
70+
},
71+
},
72+
},
73+
errors: [
74+
{
75+
code: 'xgen-IPA-114-api-error-has-bad-request-detail',
76+
message: 'ApiError schema must have badRequestDetail field.',
77+
path: ['components', 'schemas', 'ApiError'],
78+
severity: DiagnosticSeverity.Warning,
79+
},
80+
],
81+
},
82+
{
83+
name: 'badRequestDetail without fields property fails',
84+
document: {
85+
components: {
86+
schemas: {
87+
ApiError: {
88+
properties: {
89+
badRequestDetail: {
90+
properties: {
91+
someOtherProperty: { type: 'string' },
92+
},
93+
},
94+
},
95+
},
96+
},
97+
},
98+
},
99+
errors: [
100+
{
101+
code: 'xgen-IPA-114-api-error-has-bad-request-detail',
102+
message: 'badRequestDetail must include an array of fields.',
103+
path: ['components', 'schemas', 'ApiError'],
104+
severity: DiagnosticSeverity.Warning,
105+
},
106+
],
107+
},
108+
{
109+
name: 'fields not being an array fails',
110+
document: {
111+
components: {
112+
schemas: {
113+
ApiError: {
114+
properties: {
115+
badRequestDetail: {
116+
properties: {
117+
fields: {
118+
type: 'object',
119+
},
120+
},
121+
},
122+
},
123+
},
124+
},
125+
},
126+
},
127+
errors: [
128+
{
129+
code: 'xgen-IPA-114-api-error-has-bad-request-detail',
130+
message: 'badRequestDetail must include an array of fields.',
131+
path: ['components', 'schemas', 'ApiError'],
132+
severity: DiagnosticSeverity.Warning,
133+
},
134+
],
135+
},
136+
{
137+
name: 'missing description or field properties fails',
138+
document: {
139+
components: {
140+
schemas: {
141+
ApiError: {
142+
properties: {
143+
badRequestDetail: {
144+
properties: {
145+
fields: {
146+
type: 'array',
147+
properties: {
148+
// Missing description and field properties
149+
otherProperty: { type: 'string' },
150+
},
151+
},
152+
},
153+
},
154+
},
155+
},
156+
},
157+
},
158+
},
159+
errors: [
160+
{
161+
code: 'xgen-IPA-114-api-error-has-bad-request-detail',
162+
message: 'Each field must include description and field properties.',
163+
path: ['components', 'schemas', 'ApiError'],
164+
severity: DiagnosticSeverity.Warning,
165+
},
166+
],
167+
},
168+
]);

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
functions:
55
- IPA114ErrorResponsesReferToApiError
6+
- IPA114ApiErrorHasBadRequestDetail
67

78
rules:
89
xgen-IPA-114-error-responses-refer-to-api-error:
@@ -16,3 +17,18 @@ rules:
1617
given: '$.paths[*][*].responses[?(@property.match(/^[45]\d\d$/))]'
1718
then:
1819
function: 'IPA114ErrorResponsesReferToApiError'
20+
xgen-IPA-114-api-error-has-bad-request-detail:
21+
description: |
22+
ApiError schema should have badRequestDetail field with proper structure.
23+
24+
##### Implementation details
25+
Rule checks that:
26+
- ApiError schema has badRequestDetail field
27+
- badRequestDetail must include an array of fields
28+
- Each field must include description and field properties
29+
- This rule does not allow exceptions
30+
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-114-api-error-has-bad-request-detail'
31+
severity: warn
32+
given: $.components.schemas.ApiError
33+
then:
34+
function: 'IPA114ApiErrorHasBadRequestDetail'

tools/spectral/ipa/rulesets/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,18 @@ APIs must return ApiError when errors occur
615615
##### Implementation details
616616
This rule checks that all 4xx and 5xx error responses reference the ApiError schema.
617617

618+
#### xgen-IPA-114-api-error-has-bad-request-detail
619+
620+
![warn](https://img.shields.io/badge/warning-yellow)
621+
ApiError schema should have badRequestDetail field with proper structure.
622+
623+
##### Implementation details
624+
Rule checks that:
625+
- ApiError schema has badRequestDetail field
626+
- badRequestDetail must include an array of fields
627+
- Each field must include description and field properties
628+
- This rule does not allow exceptions
629+
618630

619631

620632
### IPA-117
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { collectAdoption, collectAndReturnViolation, handleInternalError } from './utils/collectionUtils.js';
2+
3+
const RULE_NAME = 'xgen-IPA-114-api-error-has-bad-request-detail';
4+
5+
/**
6+
* Verifies that ApiError schema has badRequestDetail field with proper structure
7+
*
8+
* @param {object} input - The ApiError schema object
9+
* @param {object} _ - Rule options (unused)
10+
* @param {object} context - The context object containing path and document information
11+
*/
12+
export default (input, _, { path, documentInventory }) => {
13+
const errors = checkViolationsAndReturnErrors(input, documentInventory, path);
14+
if (errors.length > 0) {
15+
return collectAndReturnViolation(path, RULE_NAME, errors);
16+
}
17+
18+
collectAdoption(path, RULE_NAME);
19+
};
20+
21+
/**
22+
* Check for violations in ApiError schema structure
23+
*
24+
* @param {object} apiErrorSchema - The ApiError schema object to validate
25+
* @param {object} documentInventory - Contains document information
26+
* @param {Array} path - Path to the schema in the document
27+
* @returns {Array} - Array of error objects
28+
*/
29+
function checkViolationsAndReturnErrors(apiErrorSchema, documentInventory, path) {
30+
try {
31+
// ApiError should have badRequestDetail property
32+
if (!apiErrorSchema.properties?.badRequestDetail) {
33+
return [
34+
{
35+
path,
36+
message: 'ApiError schema must have badRequestDetail field.',
37+
},
38+
];
39+
}
40+
41+
//badRequestDetail must include an array of fields
42+
const badRequestDetail = apiErrorSchema.properties.badRequestDetail;
43+
if (badRequestDetail.properties?.fields?.type !== 'array') {
44+
return [
45+
{
46+
path,
47+
message: 'badRequestDetail must include an array of fields.',
48+
},
49+
];
50+
}
51+
52+
//Each field must include description and field properties
53+
const fields = badRequestDetail.properties.fields;
54+
if (!fields.items?.properties?.description && !fields.items?.properties?.field) {
55+
return [
56+
{
57+
path,
58+
message: 'Each field must include description and field properties.',
59+
},
60+
];
61+
}
62+
63+
return [];
64+
} catch (e) {
65+
handleInternalError(RULE_NAME, path, e);
66+
return [{ path, message: `Internal error during validation: ${e.message}` }];
67+
}
68+
}

0 commit comments

Comments
 (0)