From 3ff5af03d70130e1901e6118d92c94d6461ace39 Mon Sep 17 00:00:00 2001 From: Andrea Piai Date: Thu, 4 Dec 2025 13:20:39 +0100 Subject: [PATCH 1/2] Add support for body in patch API --- __mocks__/api.yaml | 13 +++ __mocks__/openapi_v3/api.yaml | 13 +++ .../__snapshots__/index.test.ts.snap | 96 +++++++++++++++++++ .../gen-api-models/__tests__/parse.test.ts | 25 +++++ src/commands/gen-api-models/parse.v3.ts | 4 +- src/commands/gen-api-models/types.ts | 2 +- 6 files changed, 150 insertions(+), 3 deletions(-) diff --git a/__mocks__/api.yaml b/__mocks__/api.yaml index b9d6025..80717e1 100644 --- a/__mocks__/api.yaml +++ b/__mocks__/api.yaml @@ -177,6 +177,19 @@ paths: description: "Created" "500": description: "Fatal error" + /patch-test-parameter-with-body-ref: + patch: + operationId: "patchTestParameterWithBodyReference" + parameters: + - name: body + in: body + schema: + $ref: "#/definitions/NewModel" + responses: + "201": + description: "Created" + "500": + description: "Fatal error" /test-parameter-with-dash/{path-param}: get: diff --git a/__mocks__/openapi_v3/api.yaml b/__mocks__/openapi_v3/api.yaml index 3b0d703..db8282e 100644 --- a/__mocks__/openapi_v3/api.yaml +++ b/__mocks__/openapi_v3/api.yaml @@ -198,6 +198,19 @@ paths: description: "Created" 500: description: "Fatal error" + /patch-test-parameter-with-body-ref: + patch: + operationId: "patchTestParameterWithBodyReference" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/NewModel" + responses: + 201: + description: "Created" + 500: + description: "Fatal error" /test-parameter-with-dash/{path-param}: get: operationId: "testParameterWithDash" diff --git a/src/commands/gen-api-models/__tests__/__snapshots__/index.test.ts.snap b/src/commands/gen-api-models/__tests__/__snapshots__/index.test.ts.snap index ec31f56..b994bea 100644 --- a/src/commands/gen-api-models/__tests__/__snapshots__/index.test.ts.snap +++ b/src/commands/gen-api-models/__tests__/__snapshots__/index.test.ts.snap @@ -933,6 +933,8 @@ import { testParameterWithBodyReferenceDefaultDecoder, PutTestParameterWithBodyReferenceT, putTestParameterWithBodyReferenceDefaultDecoder, + PatchTestParameterWithBodyReferenceT, + patchTestParameterWithBodyReferenceDefaultDecoder, TestParameterWithDashT, testParameterWithDashDefaultDecoder, TestParameterWithDashAnUnderscoreT, @@ -975,6 +977,7 @@ export type ApiOperation = TypeofApiCall & TypeofApiCall & TypeofApiCall & TypeofApiCall & + TypeofApiCall & TypeofApiCall & TypeofApiCall & TypeofApiCall & @@ -998,6 +1001,7 @@ export type ParamKeys = keyof (TypeofApiParams & TypeofApiParams & TypeofApiParams & TypeofApiParams & + TypeofApiParams & TypeofApiParams & TypeofApiParams & TypeofApiParams & @@ -1043,6 +1047,7 @@ export type WithDefaultsT< | TestParameterWithReferenceT | TestParameterWithBodyReferenceT | PutTestParameterWithBodyReferenceT + | PatchTestParameterWithBodyReferenceT | TestParameterWithDashT | TestParameterWithDashAnUnderscoreT | TestWithTwoParamsT @@ -1092,6 +1097,10 @@ export type Client< PutTestParameterWithBodyReferenceT >; + readonly patchTestParameterWithBodyReference: TypeofApiCall< + PatchTestParameterWithBodyReferenceT + >; + readonly testParameterWithDash: TypeofApiCall; readonly testParameterWithDashAnUnderscore: TypeofApiCall< @@ -1193,6 +1202,13 @@ export type Client< > >; + readonly patchTestParameterWithBodyReference: TypeofApiCall< + ReplaceRequestParams< + PatchTestParameterWithBodyReferenceT, + Omit, K> + > + >; + readonly testParameterWithDash: TypeofApiCall< ReplaceRequestParams< TestParameterWithDashT, @@ -1554,6 +1570,35 @@ export function createClient({ options ); + const patchTestParameterWithBodyReferenceT: ReplaceRequestParams< + PatchTestParameterWithBodyReferenceT, + RequestParams + > = { + method: \\"patch\\", + + headers: ({ [\\"customToken\\"]: customToken }) => ({ + \\"custom-token\\": customToken, + + \\"Content-Type\\": \\"application/json\\" + }), + response_decoder: patchTestParameterWithBodyReferenceDefaultDecoder(), + url: ({}) => \`\${basePath}/patch-test-parameter-with-body-ref\`, + + body: ({ [\\"body\\"]: body }) => + body?.constructor?.name === \\"Readable\\" || + body?.constructor?.name === \\"ReadableStream\\" + ? (body as ReadableStream) + : body?.constructor?.name === \\"Buffer\\" + ? (body as Buffer) + : JSON.stringify(body), + + query: () => withoutUndefinedValues({}) + }; + const patchTestParameterWithBodyReference: TypeofApiCall = createFetchRequestForApi( + patchTestParameterWithBodyReferenceT, + options + ); + const testParameterWithDashT: ReplaceRequestParams< TestParameterWithDashT, RequestParams @@ -1829,6 +1874,9 @@ export function createClient({ putTestParameterWithBodyReference: (withDefaults || identity)( putTestParameterWithBodyReference ), + patchTestParameterWithBodyReference: (withDefaults || identity)( + patchTestParameterWithBodyReference + ), testParameterWithDash: (withDefaults || identity)(testParameterWithDash), testParameterWithDashAnUnderscore: (withDefaults || identity)( testParameterWithDashAnUnderscore @@ -2921,6 +2969,8 @@ import { testParameterWithBodyReferenceDefaultDecoder, PutTestParameterWithBodyReferenceT, putTestParameterWithBodyReferenceDefaultDecoder, + PatchTestParameterWithBodyReferenceT, + patchTestParameterWithBodyReferenceDefaultDecoder, TestParameterWithDashT, testParameterWithDashDefaultDecoder, TestParameterWithDashAnUnderscoreT, @@ -2964,6 +3014,7 @@ export type ApiOperation = TypeofApiCall & TypeofApiCall & TypeofApiCall & TypeofApiCall & + TypeofApiCall & TypeofApiCall & TypeofApiCall & TypeofApiCall & @@ -2988,6 +3039,7 @@ export type ParamKeys = keyof (TypeofApiParams & TypeofApiParams & TypeofApiParams & TypeofApiParams & + TypeofApiParams & TypeofApiParams & TypeofApiParams & TypeofApiParams & @@ -3034,6 +3086,7 @@ export type WithDefaultsT< | TestParameterWithReferenceT | TestParameterWithBodyReferenceT | PutTestParameterWithBodyReferenceT + | PatchTestParameterWithBodyReferenceT | TestParameterWithDashT | TestParameterWithDashAnUnderscoreT | TestWithTwoParamsT @@ -3085,6 +3138,10 @@ export type Client< PutTestParameterWithBodyReferenceT >; + readonly patchTestParameterWithBodyReference: TypeofApiCall< + PatchTestParameterWithBodyReferenceT + >; + readonly testParameterWithDash: TypeofApiCall; readonly testParameterWithDashAnUnderscore: TypeofApiCall< @@ -3193,6 +3250,13 @@ export type Client< > >; + readonly patchTestParameterWithBodyReference: TypeofApiCall< + ReplaceRequestParams< + PatchTestParameterWithBodyReferenceT, + Omit, K> + > + >; + readonly testParameterWithDash: TypeofApiCall< ReplaceRequestParams< TestParameterWithDashT, @@ -3584,6 +3648,35 @@ export function createClient({ options ); + const patchTestParameterWithBodyReferenceT: ReplaceRequestParams< + PatchTestParameterWithBodyReferenceT, + RequestParams + > = { + method: \\"patch\\", + + headers: ({ [\\"customToken\\"]: customToken }) => ({ + \\"custom-token\\": customToken, + + \\"Content-Type\\": \\"application/json\\" + }), + response_decoder: patchTestParameterWithBodyReferenceDefaultDecoder(), + url: ({}) => \`\${basePath}/patch-test-parameter-with-body-ref\`, + + body: ({ [\\"body\\"]: body }) => + body?.constructor?.name === \\"Readable\\" || + body?.constructor?.name === \\"ReadableStream\\" + ? (body as ReadableStream) + : body?.constructor?.name === \\"Buffer\\" + ? (body as Buffer) + : JSON.stringify(body), + + query: () => withoutUndefinedValues({}) + }; + const patchTestParameterWithBodyReference: TypeofApiCall = createFetchRequestForApi( + patchTestParameterWithBodyReferenceT, + options + ); + const testParameterWithDashT: ReplaceRequestParams< TestParameterWithDashT, RequestParams @@ -3860,6 +3953,9 @@ export function createClient({ putTestParameterWithBodyReference: (withDefaults || identity)( putTestParameterWithBodyReference ), + patchTestParameterWithBodyReference: (withDefaults || identity)( + patchTestParameterWithBodyReference + ), testParameterWithDash: (withDefaults || identity)(testParameterWithDash), testParameterWithDashAnUnderscore: (withDefaults || identity)( testParameterWithDashAnUnderscore diff --git a/src/commands/gen-api-models/__tests__/parse.test.ts b/src/commands/gen-api-models/__tests__/parse.test.ts index f2c19bd..26ce789 100644 --- a/src/commands/gen-api-models/__tests__/parse.test.ts +++ b/src/commands/gen-api-models/__tests__/parse.test.ts @@ -240,6 +240,31 @@ describe.each` ); }); + it("should parse a patch operation with body as ref", () => { + const parsed = getParser(spec).parseOperation( + //@ts-ignore + spec, + "/patch-test-parameter-with-body-ref", + [], + "undefined", + "undefined" + )("patch"); + + expect(parsed).toEqual( + expect.objectContaining({ + method: "patch", + path: "/patch-test-parameter-with-body-ref", + parameters: expect.arrayContaining([ + { + name: "body?", + in: "body", + type: "NewModel | ReadableStream | Buffer" + } + ]) + }) + ); + }); + it("should parse an operation with header parameters", () => { const parsed = getParser(spec).parseOperation( //@ts-ignore diff --git a/src/commands/gen-api-models/parse.v3.ts b/src/commands/gen-api-models/parse.v3.ts index e1f4c47..6db0984 100644 --- a/src/commands/gen-api-models/parse.v3.ts +++ b/src/commands/gen-api-models/parse.v3.ts @@ -349,7 +349,7 @@ export const parseOperation = ( ] : [undefined, false]; const bodyParam: ReadonlyArray = - ["post", "put"].includes(method) && bodySchema + ["patch", "post", "put"].includes(method) && bodySchema ? // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore "multipart/form-data" in operation?.requestBody?.content @@ -398,7 +398,7 @@ export const parseOperation = ( ]; const contentTypeHeaders = - (method === "post" || method === "put") && + (method === "patch" || method === "post" || method === "put") && Object.keys([...operationParams, ...bodyParam]).length > 0 ? ["Content-Type"] : []; diff --git a/src/commands/gen-api-models/types.ts b/src/commands/gen-api-models/types.ts index c62a497..39a5e58 100644 --- a/src/commands/gen-api-models/types.ts +++ b/src/commands/gen-api-models/types.ts @@ -20,7 +20,7 @@ export interface IGenerateApiOptions { /** * Supported http methods */ -export type SupportedMethod = "get" | "post" | "put" | "delete"; +export type SupportedMethod = "get" | "patch" | "post" | "put" | "delete"; export type SupportedAuthScheme = "bearer" | "digest" | "none"; From ac95944a04995a263da6054d693c4ffa6ccf9259 Mon Sep 17 00:00:00 2001 From: Andrea Piai Date: Thu, 4 Dec 2025 14:16:41 +0100 Subject: [PATCH 2/2] Copilot suggestion --- src/commands/gen-api-models/__tests__/parse.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/gen-api-models/__tests__/parse.test.ts b/src/commands/gen-api-models/__tests__/parse.test.ts index 26ce789..99c7296 100644 --- a/src/commands/gen-api-models/__tests__/parse.test.ts +++ b/src/commands/gen-api-models/__tests__/parse.test.ts @@ -254,6 +254,7 @@ describe.each` expect.objectContaining({ method: "patch", path: "/patch-test-parameter-with-body-ref", + consumes: "application/json", parameters: expect.arrayContaining([ { name: "body?",