diff --git a/src/templates/core/OpenAPI.hbs b/src/templates/core/OpenAPI.hbs index 270f0bfc0..3f9113697 100644 --- a/src/templates/core/OpenAPI.hbs +++ b/src/templates/core/OpenAPI.hbs @@ -1,12 +1,33 @@ {{>header}} + +{{#equals @root.httpClient 'fetch'}}{{>fetch/responseType}}{{/equals}} +{{#equals @root.httpClient 'xhr'}}{{>xhr/responseType}}{{/equals}} +{{#equals @root.httpClient 'node'}}{{>node/responseType}}{{/equals}} + type Resolver = () => Promise; type Headers = Record; +import { ApiResult } from './ApiResult'; +import { ApiRequestOptions } from './ApiRequestOptions'; + +export interface RequestHookParams { + url: string; + options: ApiRequestOptions; +} + +export interface ResponseHookParams { + url: string; + result: ApiResult; + response?: ResponseImplementation; +} + type Config = { BASE: string; VERSION: string; WITH_CREDENTIALS: boolean; + REQUEST_HOOK?(params: RequestHookParams): Promise; + RESPONSE_HOOK?(result: ResponseHookParams): Promise TOKEN?: string | Resolver; USERNAME?: string | Resolver; PASSWORD?: string | Resolver; diff --git a/src/templates/core/fetch/getResponseBody.hbs b/src/templates/core/fetch/getResponseBody.hbs index 502979ef4..d13f47b8d 100644 --- a/src/templates/core/fetch/getResponseBody.hbs +++ b/src/templates/core/fetch/getResponseBody.hbs @@ -2,9 +2,18 @@ async function getResponseBody(response: Response): Promise { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const isJSON = contentType.toLowerCase().startsWith('application/json'); + + const jsonTypes = ['application/json', 'application/problem+json'] + const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); + + //Check for the blob types + const blobTypes = ['application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] + const isBlob = blobTypes.some(type => contentType.toLowerCase().startsWith(type)); + if (isJSON) { - return await response.json(); + return await response.json(); + } else if (isBlob) { + return await response.arrayBuffer(); } else { return await response.text(); } diff --git a/src/templates/core/fetch/request.hbs b/src/templates/core/fetch/request.hbs index 5e6f47e23..03721670d 100644 --- a/src/templates/core/fetch/request.hbs +++ b/src/templates/core/fetch/request.hbs @@ -55,18 +55,30 @@ import { OpenAPI } from './OpenAPI'; */ export async function request(options: ApiRequestOptions): Promise { const url = getUrl(options); - const response = await sendRequest(options, url); + + // Pre-hook on request if a function is provided. + const requestHookResult = OpenAPI.REQUEST_HOOK ? + (await OpenAPI.REQUEST_HOOK({ url, options})) : { url, options }; + + + const response = await sendRequest(requestHookResult.options, requestHookResult.url); const responseBody = await getResponseBody(response); - const responseHeader = getResponseHeader(response, options.responseHeader); + const responseHeader = getResponseHeader(response, requestHookResult.options.responseHeader); + - const result: ApiResult = { + let result: ApiResult = { url, ok: response.ok, status: response.status, statusText: response.statusText, - body: responseHeader || responseBody, + body: responseHeader || responseBody }; + // Post-request Hook if provided + result = OpenAPI.RESPONSE_HOOK ? await OpenAPI.RESPONSE_HOOK({url, result, response}) : result; + catchErrors(options, result); + + return result; } diff --git a/src/templates/core/fetch/responseType.hbs b/src/templates/core/fetch/responseType.hbs new file mode 100644 index 000000000..c9cf71bbe --- /dev/null +++ b/src/templates/core/fetch/responseType.hbs @@ -0,0 +1,2 @@ +type ResponseImplementation = Response; + diff --git a/src/templates/core/node/request.hbs b/src/templates/core/node/request.hbs index 2c3a52478..18532dfd4 100644 --- a/src/templates/core/node/request.hbs +++ b/src/templates/core/node/request.hbs @@ -59,18 +59,26 @@ import { OpenAPI } from './OpenAPI'; */ export async function request(options: ApiRequestOptions): Promise { const url = getUrl(options); - const response = await sendRequest(options, url); + + // Pre-hook on request if a function is provided. + const requestHookResult = OpenAPI.REQUEST_HOOK ? + (await OpenAPI.REQUEST_HOOK({ url, options})) : { url, options }; + + const response = await sendRequest(requestHookResult.options, requestHookResult.url); const responseBody = await getResponseBody(response); - const responseHeader = getResponseHeader(response, options.responseHeader); + const responseHeader = getResponseHeader(response, requestHookResult.options.responseHeader); const result: ApiResult = { url, ok: response.ok, status: response.status, statusText: response.statusText, - body: responseHeader || responseBody, + body: responseHeader || responseBody }; + // Post-request Hook if provided + result = OpenAPI.RESPONSE_HOOK ? await OpenAPI.RESPONSE_HOOK({url, result, response}) : result; + catchErrors(options, result); return result; } diff --git a/src/templates/core/node/responseType.hbs b/src/templates/core/node/responseType.hbs new file mode 100644 index 000000000..556ef6d1f --- /dev/null +++ b/src/templates/core/node/responseType.hbs @@ -0,0 +1 @@ +import { Response as ResponseImplementation } from 'node-fetch'; diff --git a/src/templates/core/xhr/request.hbs b/src/templates/core/xhr/request.hbs index 88f05c6df..5755f2da7 100644 --- a/src/templates/core/xhr/request.hbs +++ b/src/templates/core/xhr/request.hbs @@ -58,18 +58,27 @@ import { OpenAPI } from './OpenAPI'; */ export async function request(options: ApiRequestOptions): Promise { const url = getUrl(options); - const response = await sendRequest(options, url); - const responseBody = getResponseBody(response); - const responseHeader = getResponseHeader(response, options.responseHeader); + + // Pre-hook on request if a function is provided. + const requestHookResult = OpenAPI.REQUEST_HOOK ? + (await OpenAPI.REQUEST_HOOK({ url, options})) : { url, options }; + + const response = await sendRequest(requestHookResult.options, requestHookResult.url); + const responseBody = await getResponseBody(response); + const responseHeader = getResponseHeader(response, requestHookResult.options.responseHeader); + const result: ApiResult = { url, ok: isSuccess(response.status), status: response.status, statusText: response.statusText, - body: responseHeader || responseBody, + body: responseHeader || responseBody }; + // Post-request Hook if provided + result = OpenAPI.RESPONSE_HOOK ? await OpenAPI.RESPONSE_HOOK({url, result, response}) : result; + catchErrors(options, result); return result; } diff --git a/src/templates/core/xhr/responseType.hbs b/src/templates/core/xhr/responseType.hbs new file mode 100644 index 000000000..5d12c9f2f --- /dev/null +++ b/src/templates/core/xhr/responseType.hbs @@ -0,0 +1 @@ +type ResponseImplementation = XMLHttpRequest; diff --git a/src/utils/registerHandlebarTemplates.ts b/src/utils/registerHandlebarTemplates.ts index febe94f1f..f6fabae84 100644 --- a/src/utils/registerHandlebarTemplates.ts +++ b/src/utils/registerHandlebarTemplates.ts @@ -9,6 +9,7 @@ import fetchGetResponseBody from '../templates/core/fetch/getResponseBody.hbs'; import fetchGetResponseHeader from '../templates/core/fetch/getResponseHeader.hbs'; import fetchRequest from '../templates/core/fetch/request.hbs'; import fetchSendRequest from '../templates/core/fetch/sendRequest.hbs'; +import fetchResponseType from '../templates/core/fetch/responseType.hbs'; import functionCatchErrors from '../templates/core/functions/catchErrors.hbs'; import functionGetFormData from '../templates/core/functions/getFormData.hbs'; import functionGetQueryString from '../templates/core/functions/getQueryString.hbs'; @@ -26,6 +27,7 @@ import nodeGetResponseBody from '../templates/core/node/getResponseBody.hbs'; import nodeGetResponseHeader from '../templates/core/node/getResponseHeader.hbs'; import nodeRequest from '../templates/core/node/request.hbs'; import nodeSendRequest from '../templates/core/node/sendRequest.hbs'; +import nodeResponseType from '../templates/core/node/responseType.hbs'; import templateCoreSettings from '../templates/core/OpenAPI.hbs'; import templateCoreRequest from '../templates/core/request.hbs'; import xhrGetHeaders from '../templates/core/xhr/getHeaders.hbs'; @@ -34,6 +36,7 @@ import xhrGetResponseBody from '../templates/core/xhr/getResponseBody.hbs'; import xhrGetResponseHeader from '../templates/core/xhr/getResponseHeader.hbs'; import xhrRequest from '../templates/core/xhr/request.hbs'; import xhrSendRequest from '../templates/core/xhr/sendRequest.hbs'; +import xhrResponseType from '../templates/core/xhr/responseType.hbs'; import templateExportModel from '../templates/exportModel.hbs'; import templateExportSchema from '../templates/exportSchema.hbs'; import templateExportService from '../templates/exportService.hbs'; @@ -154,6 +157,7 @@ export function registerHandlebarTemplates(): Templates { Handlebars.registerPartial('fetch/getResponseHeader', Handlebars.template(fetchGetResponseHeader)); Handlebars.registerPartial('fetch/sendRequest', Handlebars.template(fetchSendRequest)); Handlebars.registerPartial('fetch/request', Handlebars.template(fetchRequest)); + Handlebars.registerPartial('fetch/responseType', Handlebars.template(fetchResponseType)); // Specific files for the xhr client implementation Handlebars.registerPartial('xhr/getHeaders', Handlebars.template(xhrGetHeaders)); @@ -162,6 +166,7 @@ export function registerHandlebarTemplates(): Templates { Handlebars.registerPartial('xhr/getResponseHeader', Handlebars.template(xhrGetResponseHeader)); Handlebars.registerPartial('xhr/sendRequest', Handlebars.template(xhrSendRequest)); Handlebars.registerPartial('xhr/request', Handlebars.template(xhrRequest)); + Handlebars.registerPartial('xhr/responseType', Handlebars.template(xhrResponseType)); // Specific files for the node client implementation Handlebars.registerPartial('node/getHeaders', Handlebars.template(nodeGetHeaders)); @@ -170,6 +175,7 @@ export function registerHandlebarTemplates(): Templates { Handlebars.registerPartial('node/getResponseHeader', Handlebars.template(nodeGetResponseHeader)); Handlebars.registerPartial('node/sendRequest', Handlebars.template(nodeSendRequest)); Handlebars.registerPartial('node/request', Handlebars.template(nodeRequest)); + Handlebars.registerPartial('node/responseType', Handlebars.template(nodeResponseType)); return templates; } diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index f2cf43292..3b210cae1 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -57,13 +57,34 @@ exports[`v2 should generate: ./test/generated/v2/core/OpenAPI.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ + +type ResponseImplementation = Response; + + + type Resolver = () => Promise; type Headers = Record; +import { ApiResult } from './ApiResult'; +import { ApiRequestOptions } from './ApiRequestOptions'; + +export interface RequestHookParams { + url: string; + options: ApiRequestOptions; +} + +export interface ResponseHookParams { + url: string; + result: ApiResult; + response?: ResponseImplementation; +} + type Config = { BASE: string; VERSION: string; WITH_CREDENTIALS: boolean; + REQUEST_HOOK?(params: RequestHookParams): Promise; + RESPONSE_HOOK?(result: ResponseHookParams): Promise TOKEN?: string | Resolver; USERNAME?: string | Resolver; PASSWORD?: string | Resolver; @@ -268,19 +289,31 @@ function catchErrors(options: ApiRequestOptions, result: ApiResult): void { */ export async function request(options: ApiRequestOptions): Promise { const url = getUrl(options); - const response = await sendRequest(options, url); + + // Pre-hook on request if a function is provided. + const requestHookResult = OpenAPI.REQUEST_HOOK ? + (await OpenAPI.REQUEST_HOOK({ url, options})) : { url, options }; + + + const response = await sendRequest(requestHookResult.options, requestHookResult.url); const responseBody = await getResponseBody(response); - const responseHeader = getResponseHeader(response, options.responseHeader); + const responseHeader = getResponseHeader(response, requestHookResult.options.responseHeader); - const result: ApiResult = { + + let result: ApiResult = { url, ok: response.ok, status: response.status, statusText: response.statusText, - body: responseHeader || responseBody, + body: responseHeader || responseBody }; + // Post-request Hook if provided + result = OpenAPI.RESPONSE_HOOK ? await OpenAPI.RESPONSE_HOOK({url, result, response}) : result; + catchErrors(options, result); + + return result; } @@ -2298,13 +2331,34 @@ exports[`v3 should generate: ./test/generated/v3/core/OpenAPI.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ + +type ResponseImplementation = Response; + + + type Resolver = () => Promise; type Headers = Record; +import { ApiResult } from './ApiResult'; +import { ApiRequestOptions } from './ApiRequestOptions'; + +export interface RequestHookParams { + url: string; + options: ApiRequestOptions; +} + +export interface ResponseHookParams { + url: string; + result: ApiResult; + response?: ResponseImplementation; +} + type Config = { BASE: string; VERSION: string; WITH_CREDENTIALS: boolean; + REQUEST_HOOK?(params: RequestHookParams): Promise; + RESPONSE_HOOK?(result: ResponseHookParams): Promise TOKEN?: string | Resolver; USERNAME?: string | Resolver; PASSWORD?: string | Resolver; @@ -2509,19 +2563,31 @@ function catchErrors(options: ApiRequestOptions, result: ApiResult): void { */ export async function request(options: ApiRequestOptions): Promise { const url = getUrl(options); - const response = await sendRequest(options, url); + + // Pre-hook on request if a function is provided. + const requestHookResult = OpenAPI.REQUEST_HOOK ? + (await OpenAPI.REQUEST_HOOK({ url, options})) : { url, options }; + + + const response = await sendRequest(requestHookResult.options, requestHookResult.url); const responseBody = await getResponseBody(response); - const responseHeader = getResponseHeader(response, options.responseHeader); + const responseHeader = getResponseHeader(response, requestHookResult.options.responseHeader); - const result: ApiResult = { + + let result: ApiResult = { url, ok: response.ok, status: response.status, statusText: response.statusText, - body: responseHeader || responseBody, + body: responseHeader || responseBody }; + // Post-request Hook if provided + result = OpenAPI.RESPONSE_HOOK ? await OpenAPI.RESPONSE_HOOK({url, result, response}) : result; + catchErrors(options, result); + + return result; }