-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add schema type mismatch rule (#1890)
- Loading branch information
Showing
13 changed files
with
294 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@redocly/openapi-core": minor | ||
--- | ||
|
||
Added the `no-schema-type-mismatch` rule. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
--- | ||
slug: /docs/cli/rules/oas/no-schema-type-mismatch | ||
--- | ||
|
||
# no-schema-type-mismatch | ||
|
||
Ensures that a schema's structural properties match its declared `type`. In particular: | ||
|
||
- A schema of type `object` **must not** include an `items` field. | ||
- A schema of type `array` **must not** include a `properties` field. | ||
|
||
| OAS | Compatibility | | ||
| --- | ------------- | | ||
| 2.0 | ✅ | | ||
| 3.0 | ✅ | | ||
| 3.1 | ✅ | | ||
|
||
```mermaid | ||
flowchart TD | ||
Schema -->|if type is object| CheckItems["'items' field exists?"] | ||
Schema -->|if type is array| CheckProps["'properties' field exists?"] | ||
``` | ||
|
||
## API design principles | ||
|
||
When designing an API schema, the defined `type` should be consistent with its structure: | ||
|
||
- **Objects** are collections of key/value pairs. They should be defined using `properties` (or additionalProperties) and must not use `items`. | ||
- **Arrays** are ordered lists of items and must use `items` to define their content. Including `properties` is invalid. | ||
|
||
This rule helps catch typos and misconfigurations early in your API definition. | ||
|
||
## Configuration | ||
|
||
| Option | Type | Description | | ||
| -------- | ------ | --------------------------------------------------------------------------------------------- | | ||
| severity | string | Possible values: `off`, `warn`, `error`. Default is `error` in the recommended configuration. | | ||
|
||
Example configuration: | ||
|
||
```yaml | ||
rules: | ||
no-schema-type-mismatch: error | ||
``` | ||
## Examples | ||
### Incorrect Examples | ||
#### Object type with an `items` field | ||
|
||
```yaml | ||
properties: | ||
user: | ||
type: object | ||
properties: | ||
id: | ||
type: string | ||
items: | ||
type: number | ||
``` | ||
|
||
_Error:_ An `object` type should not include an `items` field. | ||
|
||
#### Array type with a `properties` field | ||
|
||
```yaml | ||
properties: | ||
tags: | ||
type: array | ||
properties: | ||
name: | ||
type: string | ||
``` | ||
|
||
_Error:_ An `array` type should not include a `properties` field. | ||
|
||
### Correct Examples | ||
|
||
#### Object type with proper `properties` | ||
|
||
```yaml | ||
properties: | ||
user: | ||
type: object | ||
properties: | ||
id: | ||
type: string | ||
name: | ||
type: string | ||
``` | ||
|
||
#### Array type with proper `items` | ||
|
||
```yaml | ||
properties: | ||
tags: | ||
type: array | ||
items: | ||
type: string | ||
``` | ||
|
||
## Related rules | ||
|
||
- [configurable rules](../configurable-rules.md) | ||
- [no-invalid-media-type-examples](./no-invalid-media-type-examples.md) | ||
- [no-invalid-parameter-examples](./no-invalid-parameter-examples.md) | ||
- [no-invalid-schema-examples](./no-invalid-schema-examples.md) | ||
|
||
## Resources | ||
|
||
- [Rule source](https://github.com/Redocly/redocly-cli/blob/main/packages/core/src/rules/common/no-schema-type-mismatch.ts) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
packages/core/src/rules/common/__tests__/no-schema-type-mismatch.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { outdent } from 'outdent'; | ||
import { makeConfig, parseYamlToDocument, replaceSourceWithRef } from '../../../../__tests__/utils'; | ||
import { lintDocument } from '../../../lint'; | ||
import { BaseResolver } from '../../../resolve'; | ||
|
||
describe('no-schema-type-mismatch rule', () => { | ||
it('should report a warning for object type with items field', async () => { | ||
const yaml = outdent` | ||
openapi: 3.0.0 | ||
info: | ||
title: Test API | ||
version: 1.0.0 | ||
paths: | ||
/test: | ||
get: | ||
responses: | ||
'200': | ||
description: OK | ||
content: | ||
application/json: | ||
schema: | ||
type: object | ||
items: | ||
type: string | ||
`; | ||
|
||
const document = parseYamlToDocument(yaml, 'test.yaml'); | ||
const results = await lintDocument({ | ||
document, | ||
externalRefResolver: new BaseResolver(), | ||
config: await makeConfig({ rules: { 'no-schema-type-mismatch': 'warn' } }), | ||
}); | ||
|
||
expect(replaceSourceWithRef(results)).toEqual([ | ||
{ | ||
location: [ | ||
{ | ||
pointer: '#/paths/~1test/get/responses/200/content/application~1json/schema/items', | ||
reportOnKey: false, | ||
source: 'test.yaml', | ||
}, | ||
], | ||
message: "Schema type mismatch: 'object' type should not contain 'items' field.", | ||
ruleId: 'no-schema-type-mismatch', | ||
severity: 'warn', | ||
suggest: [], | ||
}, | ||
]); | ||
}); | ||
|
||
it('should report a warning for array type with properties field', async () => { | ||
const yaml = outdent` | ||
openapi: 3.0.0 | ||
info: | ||
title: Test API | ||
version: 1.0.0 | ||
paths: | ||
/test: | ||
get: | ||
responses: | ||
'200': | ||
description: OK | ||
content: | ||
application/json: | ||
schema: | ||
type: array | ||
properties: | ||
name: | ||
type: string | ||
`; | ||
|
||
const document = parseYamlToDocument(yaml, 'test.yaml'); | ||
const results = await lintDocument({ | ||
document, | ||
externalRefResolver: new BaseResolver(), | ||
config: await makeConfig({ rules: { 'no-schema-type-mismatch': 'warn' } }), | ||
}); | ||
|
||
expect(replaceSourceWithRef(results)).toEqual([ | ||
{ | ||
location: [ | ||
{ | ||
pointer: '#/paths/~1test/get/responses/200/content/application~1json/schema/properties', | ||
reportOnKey: false, | ||
source: 'test.yaml', | ||
}, | ||
], | ||
message: "Schema type mismatch: 'array' type should not contain 'properties' field.", | ||
ruleId: 'no-schema-type-mismatch', | ||
severity: 'warn', | ||
suggest: [], | ||
}, | ||
]); | ||
}); | ||
|
||
it('should not report a warning for valid schemas', async () => { | ||
const yaml = outdent` | ||
openapi: 3.0.0 | ||
info: | ||
title: Test API | ||
version: 1.0.0 | ||
paths: | ||
/test: | ||
get: | ||
responses: | ||
'200': | ||
description: OK | ||
content: | ||
application/json: | ||
schema: | ||
type: object | ||
properties: | ||
name: | ||
type: string | ||
`; | ||
|
||
const document = parseYamlToDocument(yaml, 'test.yaml'); | ||
const results = await lintDocument({ | ||
document, | ||
externalRefResolver: new BaseResolver(), | ||
config: await makeConfig({ rules: { 'no-schema-type-mismatch': 'warn' } }), | ||
}); | ||
|
||
expect(replaceSourceWithRef(results)).toEqual([]); | ||
}); | ||
}); |
Oops, something went wrong.
e1c065b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverage report
Test suite run success
839 tests passing in 121 suites.
Report generated by 🧪jest coverage report action from e1c065b