Skip to content

Commit 4605931

Browse files
chrisradekChristopher Radek
and
Christopher Radek
authored
openapi3 - support @encode for @query parameters (#6473)
Fixes #6463 Note - this only actually impacted `@query` for openapi3 since the special array encodings aren't actually valid for headers to begin with. However the array encoding formats will be removed now for header parameters if they were for some reason used. --------- Co-authored-by: Christopher Radek <[email protected]>
1 parent e0a9683 commit 4605931

File tree

4 files changed

+53
-1
lines changed

4 files changed

+53
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@typespec/openapi3"
5+
---
6+
7+
Adds support for `@encode` to specify array encodings for `@query` parameters

packages/openapi3/src/encoding.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import { type ModelProperty, Program, type Scalar, getEncode } from "@typespec/compiler";
22
import { ObjectBuilder } from "@typespec/compiler/emitter-framework";
3-
import { isHeader } from "@typespec/http";
3+
import { isHeader, isQueryParam } from "@typespec/http";
44
import type { ResolvedOpenAPI3EmitterOptions } from "./openapi.js";
55
import { getSchemaForStdScalars } from "./std-scalar-schemas.js";
66
import type { OpenAPI3Schema, OpenAPISchema3_1 } from "./types.js";
77

8+
function isParameterStyleEncoding(encoding: string | undefined): boolean {
9+
if (!encoding) return false;
10+
return ["ArrayEncoding.pipeDelimited", "ArrayEncoding.spaceDelimited"].includes(encoding);
11+
}
12+
813
export function applyEncoding(
914
program: Program,
1015
typespecType: Scalar | ModelProperty,
@@ -17,6 +22,10 @@ export function applyEncoding(
1722

1823
const encodeData = getEncode(program, typespecType);
1924
if (encodeData) {
25+
// Query parameters have a couple of special cases where encoding ends up as style.
26+
if (isQueryParam(program, typespecType) && isParameterStyleEncoding(encodeData.encoding)) {
27+
return targetObject;
28+
}
2029
const newType = getSchemaForStdScalars(encodeData.type as any, options);
2130
targetObject.type = newType.type;
2231
// If the target already has a format it takes priority. (e.g. int32)

packages/openapi3/src/openapi.ts

+19
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
getAllTags,
1010
getAnyExtensionFromPath,
1111
getDoc,
12+
getEncode,
1213
getFormat,
1314
getMaxItems,
1415
getMaxLength,
@@ -1415,6 +1416,7 @@ function createOAPIEmitter(
14151416
applyIntrinsicDecorators(param, typeSchema),
14161417
options,
14171418
);
1419+
14181420
if (param.defaultValue) {
14191421
schema.default = getDefaultValue(program, param.defaultValue, param);
14201422
}
@@ -1510,9 +1512,26 @@ function createOAPIEmitter(
15101512
// For query parameters(style: form) the default is explode: true https://spec.openapis.org/oas/v3.0.2#fixed-fields-9
15111513
attributes.explode = false;
15121514
}
1515+
const style = getParameterStyle(httpProperty.property);
1516+
if (style) {
1517+
attributes.style = style;
1518+
}
1519+
15131520
return attributes;
15141521
}
15151522

1523+
function getParameterStyle(type: ModelProperty): string | undefined {
1524+
const encode = getEncode(program, type);
1525+
if (!encode) return;
1526+
1527+
if (encode.encoding === "ArrayEncoding.pipeDelimited") {
1528+
return "pipeDelimited";
1529+
} else if (encode.encoding === "ArrayEncoding.spaceDelimited") {
1530+
return "spaceDelimited";
1531+
}
1532+
return;
1533+
}
1534+
15161535
function getHeaderParameterAttributes(httpProperty: HttpProperty & { kind: "header" }) {
15171536
const attributes: { style?: "simple"; explode?: boolean } = {};
15181537
if (httpProperty.options.explode) {

packages/openapi3/test/parameters.test.ts

+17
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ worksFor(["3.0.0", "3.1.0"], ({ diagnoseOpenApiFor, openApiFor }) => {
3232
strictEqual(param.name, "$select");
3333
});
3434

35+
it.each([
36+
{ encoding: "ArrayEncoding.pipeDelimited", style: "pipeDelimited" },
37+
{ encoding: "ArrayEncoding.spaceDelimited", style: "spaceDelimited" },
38+
])("can set style to $style with @encode($encoding)", async ({ encoding, style }) => {
39+
const param = await getQueryParam(
40+
`op test(@query @encode(${encoding}) myParam: string[]): void;`,
41+
);
42+
expect(param).toMatchObject({
43+
explode: false,
44+
style: style,
45+
});
46+
expect(param.schema).toStrictEqual({
47+
type: "array",
48+
items: { type: "string" },
49+
});
50+
});
51+
3552
describe("doesn't set explode if explode: true (Openapi3.0 inverse default)", () => {
3653
it("with option", async () => {
3754
const param = await getQueryParam(

0 commit comments

Comments
 (0)