Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/quiet-schemas-match.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@redocly/openapi-core': patch
'@redocly/cli': patch
---

Fixed the `no-schema-type-mismatch` rule to report `properties` on any non-`object` type and `items` on any non-`array` type, such as `type: string` with `properties`.
Previously, the rule only reported `properties` on `array` and `items` on `object`.
**Note:** Because the rule is an error in the `recommended` ruleset, descriptions that passed before may now fail.
25 changes: 21 additions & 4 deletions docs/@v2/rules/common/no-schema-type-mismatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

# no-schema-type-mismatch

Ensures that a schema's structural properties match its declared `type`. In particular:

Check warning on line 7 in docs/@v2/rules/common/no-schema-type-mismatch.md

View workflow job for this annotation

GitHub Actions / recheck

recheck/semantic-line-breaks

Use semantic line breaks (sentence mode).

- A schema of type `object` **must not** include an `items` field.
- A schema of type `array` **must not** include a `properties` field.
- Only a schema of type `array` may include an `items` field.
- Only a schema of type `object` may include a `properties` field.
Comment on lines +9 to +10

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c4ef559. The docs now say the rule only checks single-value type, and a new test asserts that type: [object, 'null'] with properties reports nothing.


The rule checks only schemas whose `type` is a single value.
Schemas with a list of types, such as `type: [string, 'null']`, are not checked.

| OAS | Compatibility |
| --- | ------------- |
Expand All @@ -27,16 +30,17 @@

```mermaid
flowchart TD
Schema -->|if type is object| CheckItems["'items' field exists?"]
Schema -->|if type is array| CheckProps["'properties' field exists?"]
Schema -->|if type is not array| CheckItems["'items' field exists?"]
Schema -->|if type is not object| 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`.

Check warning on line 41 in docs/@v2/rules/common/no-schema-type-mismatch.md

View workflow job for this annotation

GitHub Actions / recheck

recheck/semantic-line-breaks

Use semantic line breaks (sentence mode).

Check notice on line 41 in docs/@v2/rules/common/no-schema-type-mismatch.md

View workflow job for this annotation

GitHub Actions / recheck

technical-english/passive-voice

Prefer the active voice; ASD-STE100 recommends it ("be defined").
- **Arrays** are ordered lists of items and must use `items` to define their content. Including `properties` is invalid.

Check warning on line 42 in docs/@v2/rules/common/no-schema-type-mismatch.md

View workflow job for this annotation

GitHub Actions / recheck

recheck/semantic-line-breaks

Use semantic line breaks (sentence mode).

Check notice on line 42 in docs/@v2/rules/common/no-schema-type-mismatch.md

View workflow job for this annotation

GitHub Actions / recheck

technical-english/passive-voice

Prefer the active voice; ASD-STE100 recommends it ("are ordered").
- **Primitive types** (`string`, `number`, `integer`, `boolean`, `null`) have neither `properties` nor `items`.

This rule helps catch typos and misconfigurations early in your API definition.

Expand Down Expand Up @@ -85,6 +89,19 @@

_Error:_ An `array` type should not include a `properties` field.

#### Primitive type with a `properties` field

```yaml
properties:
notification_email:
type: string
properties:
address:
type: string
```

_Error:_ A `string` type should not include a `properties` field.

### Correct Examples

#### Object type with proper `properties`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,106 @@ describe('no-schema-type-mismatch rule', () => {
]);
});

it('should report a warning for non-object types with properties and non-array types with items', async () => {
const yaml = outdent`
openapi: 3.1.0
info:
title: Test API
version: 1.0.0
paths:
/test:
put:
requestBody:
content:
application/json:
schema:
type: string
properties:
email:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: integer
items:
type: string
`;

const document = parseYamlToDocument(yaml, 'test.yaml');
const results = await lintDocument({
document,
externalRefResolver: new BaseResolver(),
config: await createConfig({ rules: { 'no-schema-type-mismatch': 'warn' } }),
});

expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[
{
"location": [
{
"pointer": "#/paths/~1test/put/requestBody/content/application~1json/schema/properties",
"reportOnKey": false,
"source": "test.yaml",
},
],
"message": "Schema type mismatch: 'string' type should not contain 'properties' field.",
"reference": "https://redocly.com/docs/cli/rules/common/no-schema-type-mismatch",
"ruleId": "no-schema-type-mismatch",
"severity": "warn",
"suggest": [],
},
{
"location": [
{
"pointer": "#/paths/~1test/put/responses/200/content/application~1json/schema/items",
"reportOnKey": false,
"source": "test.yaml",
},
],
"message": "Schema type mismatch: 'integer' type should not contain 'items' field.",
"reference": "https://redocly.com/docs/cli/rules/common/no-schema-type-mismatch",
"ruleId": "no-schema-type-mismatch",
"severity": "warn",
"suggest": [],
},
]
`);
});

it('should not report a warning for schemas with a list of types', async () => {
const yaml = outdent`
openapi: 3.1.0
info:
title: Test API
version: 1.0.0
paths:
/test:
get:
responses:
'200':
description: OK
content:
application/json:
schema:
type: [object, 'null']
properties:
name:
type: string
`;

const document = parseYamlToDocument(yaml, 'test.yaml');
const results = await lintDocument({
document,
externalRefResolver: new BaseResolver(),
config: await createConfig({ rules: { 'no-schema-type-mismatch': 'warn' } }),
});

expect(replaceSourceWithRef(results)).toEqual([]);
});

it('should not report a warning for valid schemas', async () => {
const yaml = outdent`
openapi: 3.0.0
Expand Down
12 changes: 8 additions & 4 deletions packages/core/src/rules/common/no-schema-type-mismatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,21 @@ export const NoSchemaTypeMismatch:
| Arazzo1Rule = () => {
return {
Schema(schema: Oas2Schema | Oas3Schema, { report, location }: UserContext) {
if (schema.type === 'object' && schema.items) {
if (typeof schema.type !== 'string') {
return;
}

if (schema.type !== 'array' && schema.items) {
report({
message: "Schema type mismatch: 'object' type should not contain 'items' field.",
message: `Schema type mismatch: '${schema.type}' type should not contain 'items' field.`,
location: location.child('items'),
reference: 'https://redocly.com/docs/cli/rules/common/no-schema-type-mismatch',
});
}

if (schema.type === 'array' && schema.properties) {
if (schema.type !== 'object' && schema.properties) {
report({
message: "Schema type mismatch: 'array' type should not contain 'properties' field.",
message: `Schema type mismatch: '${schema.type}' type should not contain 'properties' field.`,
location: location.child('properties'),
reference: 'https://redocly.com/docs/cli/rules/common/no-schema-type-mismatch',
});
Expand Down
Loading