Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
7 changes: 7 additions & 0 deletions .changeset/young-ghosts-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@redocly/openapi-core": minor
"@redocly/cli": minor
---

Added the `spec-querystring-parameters` rule (OpenAPI 3.2).
This rule enforces that `query` and `querystring` are not mixed in the same operation/path parameter set, and that at most one `querystring` parameter is declared per operation or path.
1 change: 1 addition & 0 deletions docs/@v2/rules/built-in-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The rules list is split into sections.
- [security-defined](./oas/security-defined.md): Security rules must be defined, either globally or per-operation
- [struct](./common/struct.md): Conform to the declared OpenAPI specification version
- [spec-components-invalid-map-name](./oas/spec-components-invalid-map-name.md): Use only alphanumeric and basic punctuation as key names in the components section
- [spec-querystring-parameters](./oas/spec-querystring-parameters.md): Enforce valid use of `in: querystring` (OpenAPI 3.2): at most one per path/operation, and not mixed with `in: query`
Comment thread
n0rahh marked this conversation as resolved.
- [spec-strict-refs](./oas/spec-strict-refs.md): Restricts the usage of the `$ref` keyword

### Info
Expand Down
131 changes: 131 additions & 0 deletions docs/@v2/rules/oas/spec-querystring-parameters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
slug: /docs/cli/rules/oas/spec-querystring-parameters
---

# spec-querystring-parameters

Enforces valid use of `querystring` parameters.

| OAS | Compatibility |
| --- | ------------- |
| 2.0 | ❌ |
| 3.0 | ❌ |
| 3.1 | ❌ |
| 3.2 | ✅ |

## API design principles

OpenAPI 3.2 introduces the `querystring` parameter location for representing the full query string as a single schema (e.g. `application/x-www-form-urlencoded`).

This rule ensures that:

- There is at most one `querystring` parameter.
Parameters with `in: querystring` may be defined only once per path/operation parameter set.
- No mixing `querystring` with `query`.
Parameters with `in: query` cannot be used together with `in: querystring` in the same operation/path parameter set.

## Configuration

| Option | Type | Description |
| -------- | ------ | ------------------------------------------------------------------------------------------ |
| severity | string | Possible values: `off`, `warn`, `error`. Default `error` (in `recommended` configuration). |

An example configuration:

```yaml
rules:
spec-querystring-parameters: error
```

## Examples

Given this configuration:

```yaml
rules:
spec-querystring-parameters: error
```

Example of **incorrect** use (mixing `query` and `querystring`):

```yaml
paths:
/events:
get:
summary: List events
parameters:
- name: timezone
in: query
schema:
type: string
default: UTC
- name: criteria
in: querystring
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
startDate: { type: string, format: date }
endDate: { type: string, format: date }
status: { type: string, enum: [scheduled, cancelled, completed] }
```

Example of **incorrect** use (multiple `querystring` parameters):

```yaml
paths:
/events:
get:
summary: List events
parameters:
- name: filters
in: querystring
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
startDate: { type: string, format: date }
status: { type: string }
- name: pagination
in: querystring
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
limit: { type: integer }
offset: { type: integer }
```

Example of **correct** use (single `querystring` parameter, no `query`):

```yaml
paths:
/events:
get:
summary: List events
parameters:
- name: params
in: querystring
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
startDate: { type: string, format: date }
endDate: { type: string, format: date }
status: { type: string, enum: [scheduled, cancelled, completed] }
limit: { type: integer, default: 20 }
offset: { type: integer, default: 0 }
```

## Related rules

- [operation-parameters-unique](./operation-parameters-unique.md)

## Resources

- [Rule source](https://github.com/Redocly/redocly-cli/blob/main/packages/core/src/rules/oas3/spec-querystring-parameters.ts)
- [OpenAPI 3.2 Parameter object](https://spec.openapis.org/oas/3.2.0#parameter-object)
1 change: 1 addition & 0 deletions docs/@v2/v2.sidebars.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
- page: rules/oas/spec-example-values.md
- page: rules/oas/spec-discriminator-defaultMapping.md
- page: rules/oas/spec-no-invalid-encoding-combinations.md
- page: rules/oas/spec-querystring-parameters.md
- page: rules/oas/no-path-trailing-slash.md
- page: rules/oas/no-server-example-com.md
- page: rules/oas/no-server-trailing-slash.md
Expand Down
26 changes: 26 additions & 0 deletions packages/core/src/__tests__/bundle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,32 @@ describe('bundle', () => {
`);
});

it('should accept parameter in: querystring (OAS 3.2)', async () => {
const document = outdent`
openapi: 3.2.0
paths:
/test:
get:
parameters:
- name: filters
in: querystring
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
filters:
type: string
`;

const { problems } = await bundleFromString({
source: document,
config: await createConfig({}),
});

expect(problems).toHaveLength(0);
});

it('should pull hosted schema', async () => {
const { bundle: res, problems } = await bundle({
config: await createConfig({}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ exports[`resolveConfig > should ignore minimal from the root and read local file
"spec-example-values": "error",
"spec-no-invalid-encoding-combinations": "error",
"spec-no-invalid-tag-parents": "error",
"spec-querystring-parameters": "error",
"spec-strict-refs": "off",
"tag-description": "warn",
"tags-alphabetical": "off",
Expand Down Expand Up @@ -664,6 +665,7 @@ exports[`resolveConfig > should resolve extends with local file config which con
"spec-example-values": "error",
"spec-no-invalid-encoding-combinations": "error",
"spec-no-invalid-tag-parents": "error",
"spec-querystring-parameters": "error",
"spec-strict-refs": "off",
"tag-description": "warn",
"tags-alphabetical": "off",
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/config/__tests__/load.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ describe('loadConfig', () => {
"spec-example-values": "off",
"spec-no-invalid-encoding-combinations": "warn",
"spec-no-invalid-tag-parents": "warn",
"spec-querystring-parameters": "error",
"spec-strict-refs": "off",
"tag-description": "warn",
"tags-alphabetical": "off",
Expand Down Expand Up @@ -723,6 +724,7 @@ describe('loadConfig', () => {
"spec-example-values": "error",
"spec-no-invalid-encoding-combinations": "error",
"spec-no-invalid-tag-parents": "error",
"spec-querystring-parameters": "error",
"spec-strict-refs": "off",
"tag-description": "warn",
"tags-alphabetical": "off",
Expand Down Expand Up @@ -1046,6 +1048,7 @@ describe('loadConfig', () => {
"spec-example-values": "off",
"spec-no-invalid-encoding-combinations": "warn",
"spec-no-invalid-tag-parents": "warn",
"spec-querystring-parameters": "error",
"spec-strict-refs": "error",
"tag-description": "warn",
"tags-alphabetical": "off",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ const all: RawGovernanceConfig<'built-in'> = {
'spec-no-invalid-encoding-combinations': 'error',
'spec-discriminator-defaultMapping': 'error',
'spec-example-values': 'error',
'spec-querystring-parameters': 'error',
},
async2Rules: {
'channels-kebab-case': 'error',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/minimal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ const minimal: RawGovernanceConfig<'built-in'> = {
'spec-example-values': 'off',
'spec-no-invalid-encoding-combinations': 'warn',
'spec-no-invalid-tag-parents': 'warn',
'spec-querystring-parameters': 'error',
'spec-strict-refs': 'off',
'tag-description': 'warn',
'tags-alphabetical': 'off',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/recommended-strict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ const recommendedStrict: RawGovernanceConfig<'built-in'> = {
'spec-example-values': 'error',
'spec-no-invalid-encoding-combinations': 'error',
'spec-no-invalid-tag-parents': 'error',
'spec-querystring-parameters': 'error',
'spec-strict-refs': 'off',
'tag-description': 'error',
'tags-alphabetical': 'off',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ const recommended: RawGovernanceConfig<'built-in'> = {
'spec-example-values': 'error',
'spec-no-invalid-encoding-combinations': 'error',
'spec-no-invalid-tag-parents': 'error',
'spec-querystring-parameters': 'error',
'spec-strict-refs': 'off',
'tag-description': 'warn',
'tags-alphabetical': 'off',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ const spec: RawGovernanceConfig<'built-in'> = {
'spec-example-values': 'error',
'spec-no-invalid-encoding-combinations': 'error',
'spec-no-invalid-tag-parents': 'error',
'spec-querystring-parameters': 'error',
'spec-strict-refs': 'error',
'tag-description': 'off',
'tags-alphabetical': 'off',
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export type RawGovernanceConfig<T extends 'built-in' | undefined = undefined> =
| 'spec-no-invalid-tag-parents'
| 'spec-no-invalid-encoding-combinations'
| 'spec-discriminator-defaultMapping'
| 'spec-querystring-parameters'
>,
RuleConfig,
T
Expand All @@ -80,6 +81,7 @@ export type RawGovernanceConfig<T extends 'built-in' | undefined = undefined> =
| 'spec-no-invalid-tag-parents'
| 'spec-no-invalid-encoding-combinations'
| 'spec-discriminator-defaultMapping'
| 'spec-querystring-parameters'
>,
RuleConfig,
T
Expand Down
Loading