Skip to content

Commit 31ea755

Browse files
n0rahhJLekawa
andauthored
feat: add rule to validate query and querystring parameters usage (#2551)
* feat: add rule to validate query and querystring parameter usage in OpenAPI 3.2 * fix: cr fixes * fix: enhance querystring parameter validation * fix: simplify querystring parameter error messages and improve validation logic * Apply suggestion from @JLekawa * docs: update docs * fix: keep 'spec-querystring-parameters' rule within 3.2 * docs: correct formatting in 'spec-querystring-parameters' documentation * Apply suggestions from code review * fix: docs refactor * Apply suggestion from @JLekawa --------- Co-authored-by: Jacek Łękawa <164185257+JLekawa@users.noreply.github.com>
1 parent 23ef7c4 commit 31ea755

File tree

17 files changed

+598
-0
lines changed

17 files changed

+598
-0
lines changed

.changeset/young-ghosts-drop.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@redocly/openapi-core": minor
3+
"@redocly/cli": minor
4+
---
5+
6+
Added the `spec-querystring-parameters` rule (OpenAPI 3.2).
7+
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.

docs/@v2/rules/built-in-rules.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ The rules list is split into sections.
3737
- [security-defined](./oas/security-defined.md): Security rules must be defined, either globally or per-operation
3838
- [struct](./common/struct.md): Conform to the declared OpenAPI specification version
3939
- [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
40+
- [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`
4041
- [spec-strict-refs](./oas/spec-strict-refs.md): Restricts the usage of the `$ref` keyword
4142

4243
### Info
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
slug: /docs/cli/rules/oas/spec-querystring-parameters
3+
---
4+
5+
# spec-querystring-parameters
6+
7+
Enforces valid use of `querystring` parameters.
8+
9+
| OAS | Compatibility |
10+
| --- | ------------- |
11+
| 2.0 ||
12+
| 3.0 ||
13+
| 3.1 ||
14+
| 3.2 ||
15+
16+
## API design principles
17+
18+
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`).
19+
20+
This rule ensures that:
21+
22+
- There is at most one `querystring` parameter.
23+
Parameters with `in: querystring` may be defined only once per path/operation parameter set.
24+
- No mixing `querystring` with `query`.
25+
Parameters with `in: query` cannot be used together with `in: querystring` in the same operation/path parameter set.
26+
27+
## Configuration
28+
29+
| Option | Type | Description |
30+
| -------- | ------ | ------------------------------------------------------------------------------------------ |
31+
| severity | string | Possible values: `off`, `warn`, `error`. Default `error` (in `recommended` configuration). |
32+
33+
An example configuration:
34+
35+
```yaml
36+
rules:
37+
spec-querystring-parameters: error
38+
```
39+
40+
## Examples
41+
42+
Given this configuration:
43+
44+
```yaml
45+
rules:
46+
spec-querystring-parameters: error
47+
```
48+
49+
Example of **incorrect** use (mixing `query` and `querystring`):
50+
51+
```yaml
52+
paths:
53+
/events:
54+
get:
55+
summary: List events
56+
parameters:
57+
- name: timezone
58+
in: query
59+
schema:
60+
type: string
61+
default: UTC
62+
- name: criteria
63+
in: querystring
64+
content:
65+
application/x-www-form-urlencoded:
66+
schema:
67+
type: object
68+
properties:
69+
startDate: { type: string, format: date }
70+
endDate: { type: string, format: date }
71+
status: { type: string, enum: [scheduled, cancelled, completed] }
72+
```
73+
74+
Example of **incorrect** use (multiple `querystring` parameters):
75+
76+
```yaml
77+
paths:
78+
/events:
79+
get:
80+
summary: List events
81+
parameters:
82+
- name: filters
83+
in: querystring
84+
content:
85+
application/x-www-form-urlencoded:
86+
schema:
87+
type: object
88+
properties:
89+
startDate: { type: string, format: date }
90+
status: { type: string }
91+
- name: pagination
92+
in: querystring
93+
content:
94+
application/x-www-form-urlencoded:
95+
schema:
96+
type: object
97+
properties:
98+
limit: { type: integer }
99+
offset: { type: integer }
100+
```
101+
102+
Example of **correct** use (single `querystring` parameter, no `query`):
103+
104+
```yaml
105+
paths:
106+
/events:
107+
get:
108+
summary: List events
109+
parameters:
110+
- name: params
111+
in: querystring
112+
content:
113+
application/x-www-form-urlencoded:
114+
schema:
115+
type: object
116+
properties:
117+
startDate: { type: string, format: date }
118+
endDate: { type: string, format: date }
119+
status: { type: string, enum: [scheduled, cancelled, completed] }
120+
limit: { type: integer, default: 20 }
121+
offset: { type: integer, default: 0 }
122+
```
123+
124+
## Related rules
125+
126+
- [operation-parameters-unique](./operation-parameters-unique.md)
127+
128+
## Resources
129+
130+
- [Rule source](https://github.com/Redocly/redocly-cli/blob/main/packages/core/src/rules/oas3/spec-querystring-parameters.ts)
131+
- [OpenAPI 3.2 Parameter object](https://spec.openapis.org/oas/3.2.0#parameter-object)

docs/@v2/v2.sidebars.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
- page: rules/oas/spec-example-values.md
111111
- page: rules/oas/spec-discriminator-defaultMapping.md
112112
- page: rules/oas/spec-no-invalid-encoding-combinations.md
113+
- page: rules/oas/spec-querystring-parameters.md
113114
- page: rules/oas/no-path-trailing-slash.md
114115
- page: rules/oas/no-server-example-com.md
115116
- page: rules/oas/no-server-trailing-slash.md

packages/core/src/__tests__/bundle.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,32 @@ describe('bundle', () => {
275275
`);
276276
});
277277

278+
it('should accept parameter in: querystring (OAS 3.2)', async () => {
279+
const document = outdent`
280+
openapi: 3.2.0
281+
paths:
282+
/test:
283+
get:
284+
parameters:
285+
- name: filters
286+
in: querystring
287+
content:
288+
application/x-www-form-urlencoded:
289+
schema:
290+
type: object
291+
properties:
292+
filters:
293+
type: string
294+
`;
295+
296+
const { problems } = await bundleFromString({
297+
source: document,
298+
config: await createConfig({}),
299+
});
300+
301+
expect(problems).toHaveLength(0);
302+
});
303+
278304
it('should pull hosted schema', async () => {
279305
const { bundle: res, problems } = await bundle({
280306
config: await createConfig({}),

packages/core/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ exports[`resolveConfig > should ignore minimal from the root and read local file
283283
"spec-example-values": "error",
284284
"spec-no-invalid-encoding-combinations": "error",
285285
"spec-no-invalid-tag-parents": "error",
286+
"spec-querystring-parameters": "error",
286287
"spec-strict-refs": "off",
287288
"tag-description": "warn",
288289
"tags-alphabetical": "off",
@@ -664,6 +665,7 @@ exports[`resolveConfig > should resolve extends with local file config which con
664665
"spec-example-values": "error",
665666
"spec-no-invalid-encoding-combinations": "error",
666667
"spec-no-invalid-tag-parents": "error",
668+
"spec-querystring-parameters": "error",
667669
"spec-strict-refs": "off",
668670
"tag-description": "warn",
669671
"tags-alphabetical": "off",

packages/core/src/config/__tests__/load.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ describe('loadConfig', () => {
413413
"spec-example-values": "off",
414414
"spec-no-invalid-encoding-combinations": "warn",
415415
"spec-no-invalid-tag-parents": "warn",
416+
"spec-querystring-parameters": "error",
416417
"spec-strict-refs": "off",
417418
"tag-description": "warn",
418419
"tags-alphabetical": "off",
@@ -723,6 +724,7 @@ describe('loadConfig', () => {
723724
"spec-example-values": "error",
724725
"spec-no-invalid-encoding-combinations": "error",
725726
"spec-no-invalid-tag-parents": "error",
727+
"spec-querystring-parameters": "error",
726728
"spec-strict-refs": "off",
727729
"tag-description": "warn",
728730
"tags-alphabetical": "off",
@@ -1046,6 +1048,7 @@ describe('loadConfig', () => {
10461048
"spec-example-values": "off",
10471049
"spec-no-invalid-encoding-combinations": "warn",
10481050
"spec-no-invalid-tag-parents": "warn",
1051+
"spec-querystring-parameters": "error",
10491052
"spec-strict-refs": "error",
10501053
"tag-description": "warn",
10511054
"tags-alphabetical": "off",

packages/core/src/config/all.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ const all: RawGovernanceConfig<'built-in'> = {
246246
'spec-no-invalid-encoding-combinations': 'error',
247247
'spec-discriminator-defaultMapping': 'error',
248248
'spec-example-values': 'error',
249+
'spec-querystring-parameters': 'error',
249250
},
250251
async2Rules: {
251252
'channels-kebab-case': 'error',

packages/core/src/config/minimal.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ const minimal: RawGovernanceConfig<'built-in'> = {
222222
'spec-example-values': 'off',
223223
'spec-no-invalid-encoding-combinations': 'warn',
224224
'spec-no-invalid-tag-parents': 'warn',
225+
'spec-querystring-parameters': 'error',
225226
'spec-strict-refs': 'off',
226227
'tag-description': 'warn',
227228
'tags-alphabetical': 'off',

packages/core/src/config/recommended-strict.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ const recommendedStrict: RawGovernanceConfig<'built-in'> = {
222222
'spec-example-values': 'error',
223223
'spec-no-invalid-encoding-combinations': 'error',
224224
'spec-no-invalid-tag-parents': 'error',
225+
'spec-querystring-parameters': 'error',
225226
'spec-strict-refs': 'off',
226227
'tag-description': 'error',
227228
'tags-alphabetical': 'off',

0 commit comments

Comments
 (0)