From 7abe5755e97b7eb562fbe815617d8ba2731af1bb Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Wed, 2 Nov 2022 18:29:39 +0100 Subject: [PATCH 1/3] feat: 3xx as success response code --- __mocks__/api.yaml | 12 +++++++++- __mocks__/openapi_v3/api.yaml | 12 +++++++++- e2e/src/__tests__/test-api/client.test.ts | 13 +++++++++++ .../gen-api-models/__tests__/parse.test.ts | 22 +++++++++++++++++++ src/commands/gen-api-models/render.ts | 2 +- 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/__mocks__/api.yaml b/__mocks__/api.yaml index 3a32349..d5edf7e 100644 --- a/__mocks__/api.yaml +++ b/__mocks__/api.yaml @@ -271,7 +271,17 @@ paths: responses: "200": $ref: "#/responses/NotFound" - + /test-redirect-response-header: + post: + operationId: "testRedirectResponseHeader" + responses: + "302": + description: "redirect to location" + headers: + Location: + type: string + "500": + description: "Fatal error" definitions: Person: $ref: "definitions.yaml#/Person" diff --git a/__mocks__/openapi_v3/api.yaml b/__mocks__/openapi_v3/api.yaml index 79049ee..c0e6772 100644 --- a/__mocks__/openapi_v3/api.yaml +++ b/__mocks__/openapi_v3/api.yaml @@ -299,7 +299,17 @@ paths: responses: "200": $ref: "#/components/responses/NotFound" - + /test-redirect-response-header: + post: + operationId: "testRedirectResponseHeader" + responses: + "302": + description: "redirect to location" + headers: + Location: + type: string + "500": + description: "Fatal error" # ------------- # Components # ------------- diff --git a/e2e/src/__tests__/test-api/client.test.ts b/e2e/src/__tests__/test-api/client.test.ts index f28cfba..8ce8e1f 100644 --- a/e2e/src/__tests__/test-api/client.test.ts +++ b/e2e/src/__tests__/test-api/client.test.ts @@ -340,4 +340,17 @@ describeSuite("Http client generated from Test API spec", () => { // @ts-expect-error client.putTestParameterWithBodyReference({ body: "" }); }); + + it("should make post with response 302 and location header", async () => { + const client = createClient({ + baseUrl: `http://localhost:${mockPort}`, + fetchApi: (nodeFetch as any) as typeof fetch, + basePath: "" + }); + + expect(client.testRedirectResponseHeader).toEqual(expect.any(Function)); + + const result = await client.testRedirectResponseHeader({}); + expect(isRight(result)).toBe(true); + }); }); diff --git a/src/commands/gen-api-models/__tests__/parse.test.ts b/src/commands/gen-api-models/__tests__/parse.test.ts index f8ca356..565b658 100644 --- a/src/commands/gen-api-models/__tests__/parse.test.ts +++ b/src/commands/gen-api-models/__tests__/parse.test.ts @@ -291,6 +291,28 @@ describe.each` }) ); }); + + it("should parse an operation with response with 302 and header location", () => { + const parsed = getParser(spec).parseOperation( + //@ts-ignore + spec, + "/test-redirect-response-header", + [], + "undefined", + "undefined" + )("post"); + + expect(parsed).toEqual( + expect.objectContaining({ + method: "post", + path: "/test-redirect-response-header", + parameters: [], + responses: expect.arrayContaining([ + { e1: "302", e2: "undefined", e3: ["Location"] } + ]) + }) + ); + }); }); describe.each` diff --git a/src/commands/gen-api-models/render.ts b/src/commands/gen-api-models/render.ts index 31d237c..cfa4112 100644 --- a/src/commands/gen-api-models/render.ts +++ b/src/commands/gen-api-models/render.ts @@ -207,7 +207,7 @@ export const renderOperation = ( export function renderDecoderCode({ responses, operationId }: IOperationInfo) { // use the first 2xx type as "success type" that we allow to be overridden const firstSuccessType = responses.find( - ({ e1 }) => e1.length === 3 && e1[0] === "2" + ({ e1 }) => e1.length === 3 && (e1[0] === "2" || e1[0] === "3") ); if (!firstSuccessType) { return ""; From b8a37cd54b72c05241ce20b3334cb28c899519c4 Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Wed, 2 Nov 2022 18:32:09 +0100 Subject: [PATCH 2/3] fix: comment fir renderDecoderCode --- src/commands/gen-api-models/render.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/gen-api-models/render.ts b/src/commands/gen-api-models/render.ts index cfa4112..76e97d0 100644 --- a/src/commands/gen-api-models/render.ts +++ b/src/commands/gen-api-models/render.ts @@ -205,7 +205,7 @@ export const renderOperation = ( */ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type, prefer-arrow/prefer-arrow-functions export function renderDecoderCode({ responses, operationId }: IOperationInfo) { - // use the first 2xx type as "success type" that we allow to be overridden + // use the first 2xx type and 3xx as "success type" that we allow to be overridden const firstSuccessType = responses.find( ({ e1 }) => e1.length === 3 && (e1[0] === "2" || e1[0] === "3") ); From 7e54497f3e73d573227210a2c68f84e03caeb4e8 Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Wed, 2 Nov 2022 18:40:50 +0100 Subject: [PATCH 3/3] fix: update snapshot --- .../__snapshots__/index.test.ts.snap | 100 ++++++++++++++++-- 1 file changed, 90 insertions(+), 10 deletions(-) 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 e93600b..dfc0026 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 @@ -932,7 +932,9 @@ import { TestCustomTokenHeaderT, testCustomTokenHeaderDefaultDecoder, TestWithEmptyResponseT, - testWithEmptyResponseDefaultDecoder + testWithEmptyResponseDefaultDecoder, + TestRedirectResponseHeaderT, + testRedirectResponseHeaderDefaultDecoder } from \\"./requestTypes\\"; // This is a placeholder for undefined when dealing with object keys @@ -957,7 +959,8 @@ export type ApiOperation = TypeofApiCall & TypeofApiCall & TypeofApiCall & TypeofApiCall & - TypeofApiCall; + TypeofApiCall & + TypeofApiCall; export type ParamKeys = keyof (TypeofApiParams & TypeofApiParams & @@ -975,7 +978,8 @@ export type ParamKeys = keyof (TypeofApiParams & TypeofApiParams & TypeofApiParams & TypeofApiParams & - TypeofApiParams); + TypeofApiParams & + TypeofApiParams); /** * Defines an adapter for TypeofApiCall which omit one or more parameters in the signature @@ -1015,7 +1019,8 @@ export type WithDefaultsT< | TestParametersAtPathLevelT | TestSimplePatchT | TestCustomTokenHeaderT - | TestWithEmptyResponseT, + | TestWithEmptyResponseT + | TestRedirectResponseHeaderT, K >; @@ -1070,6 +1075,10 @@ export type Client< readonly testCustomTokenHeader: TypeofApiCall; readonly testWithEmptyResponse: TypeofApiCall; + + readonly testRedirectResponseHeader: TypeofApiCall< + TestRedirectResponseHeaderT + >; } : { readonly testAuthBearer: TypeofApiCall< @@ -1190,6 +1199,13 @@ export type Client< Omit, K> > >; + + readonly testRedirectResponseHeader: TypeofApiCall< + ReplaceRequestParams< + TestRedirectResponseHeaderT, + Omit, K> + > + >; }; /** @@ -1597,6 +1613,27 @@ export function createClient({ options ); + const testRedirectResponseHeaderT: ReplaceRequestParams< + TestRedirectResponseHeaderT, + RequestParams + > = { + method: \\"post\\", + + headers: () => ({ + \\"Content-Type\\": \\"application/json\\" + }), + response_decoder: testRedirectResponseHeaderDefaultDecoder(), + url: ({}) => \`\${basePath}/test-redirect-response-header\`, + + body: () => \\"{}\\", + + query: () => withoutUndefinedValues({}) + }; + const testRedirectResponseHeader: TypeofApiCall = createFetchRequestForApi( + testRedirectResponseHeaderT, + options + ); + return { testAuthBearer: (withDefaults || identity)(testAuthBearer), testSimpleToken: (withDefaults || identity)(testSimpleToken), @@ -1624,7 +1661,10 @@ export function createClient({ ), testSimplePatch: (withDefaults || identity)(testSimplePatch), testCustomTokenHeader: (withDefaults || identity)(testCustomTokenHeader), - testWithEmptyResponse: (withDefaults || identity)(testWithEmptyResponse) + testWithEmptyResponse: (withDefaults || identity)(testWithEmptyResponse), + testRedirectResponseHeader: (withDefaults || identity)( + testRedirectResponseHeader + ) }; } " @@ -2696,7 +2736,9 @@ import { TestCustomTokenHeaderT, testCustomTokenHeaderDefaultDecoder, TestWithEmptyResponseT, - testWithEmptyResponseDefaultDecoder + testWithEmptyResponseDefaultDecoder, + TestRedirectResponseHeaderT, + testRedirectResponseHeaderDefaultDecoder } from \\"./requestTypes\\"; // This is a placeholder for undefined when dealing with object keys @@ -2722,7 +2764,8 @@ export type ApiOperation = TypeofApiCall & TypeofApiCall & TypeofApiCall & TypeofApiCall & - TypeofApiCall; + TypeofApiCall & + TypeofApiCall; export type ParamKeys = keyof (TypeofApiParams & TypeofApiParams & @@ -2741,7 +2784,8 @@ export type ParamKeys = keyof (TypeofApiParams & TypeofApiParams & TypeofApiParams & TypeofApiParams & - TypeofApiParams); + TypeofApiParams & + TypeofApiParams); /** * Defines an adapter for TypeofApiCall which omit one or more parameters in the signature @@ -2782,7 +2826,8 @@ export type WithDefaultsT< | TestParametersAtPathLevelT | TestSimplePatchT | TestCustomTokenHeaderT - | TestWithEmptyResponseT, + | TestWithEmptyResponseT + | TestRedirectResponseHeaderT, K >; @@ -2839,6 +2884,10 @@ export type Client< readonly testCustomTokenHeader: TypeofApiCall; readonly testWithEmptyResponse: TypeofApiCall; + + readonly testRedirectResponseHeader: TypeofApiCall< + TestRedirectResponseHeaderT + >; } : { readonly testAuthBearer: TypeofApiCall< @@ -2966,6 +3015,13 @@ export type Client< Omit, K> > >; + + readonly testRedirectResponseHeader: TypeofApiCall< + ReplaceRequestParams< + TestRedirectResponseHeaderT, + Omit, K> + > + >; }; /** @@ -3407,6 +3463,27 @@ export function createClient({ options ); + const testRedirectResponseHeaderT: ReplaceRequestParams< + TestRedirectResponseHeaderT, + RequestParams + > = { + method: \\"post\\", + + headers: () => ({ + \\"Content-Type\\": \\"application/json\\" + }), + response_decoder: testRedirectResponseHeaderDefaultDecoder(), + url: ({}) => \`\${basePath}/test-redirect-response-header\`, + + body: () => \\"{}\\", + + query: () => withoutUndefinedValues({}) + }; + const testRedirectResponseHeader: TypeofApiCall = createFetchRequestForApi( + testRedirectResponseHeaderT, + options + ); + return { testAuthBearer: (withDefaults || identity)(testAuthBearer), testAuthBearerHttp: (withDefaults || identity)(testAuthBearerHttp), @@ -3435,7 +3512,10 @@ export function createClient({ ), testSimplePatch: (withDefaults || identity)(testSimplePatch), testCustomTokenHeader: (withDefaults || identity)(testCustomTokenHeader), - testWithEmptyResponse: (withDefaults || identity)(testWithEmptyResponse) + testWithEmptyResponse: (withDefaults || identity)(testWithEmptyResponse), + testRedirectResponseHeader: (withDefaults || identity)( + testRedirectResponseHeader + ) }; } "