From 2eb3529d638de856f061a489d947d3af50cb7b7f Mon Sep 17 00:00:00 2001 From: Maarten Van Hoof Date: Wed, 7 Apr 2021 14:59:15 +0200 Subject: [PATCH 1/3] fix(request): respect mediaType --- src/client/interfaces/OperationParameter.d.ts | 1 + src/openApi/v2/parser/getOperationParameter.ts | 1 + src/openApi/v3/parser/getMediaType.ts | 10 ++++++++++ src/openApi/v3/parser/getOperationParameter.ts | 1 + src/openApi/v3/parser/getOperationRequestBody.ts | 4 ++++ src/templates/core/ApiRequestOptions.hbs | 1 + src/templates/core/fetch/getHeaders.hbs | 14 +++++++++----- src/templates/core/fetch/getRequestBody.hbs | 4 +++- src/templates/core/node/getHeaders.hbs | 14 +++++++++----- src/templates/core/node/getRequestBody.hbs | 4 +++- src/templates/core/xhr/getHeaders.hbs | 14 +++++++++----- src/templates/core/xhr/getRequestBody.hbs | 4 +++- src/templates/exportService.hbs | 3 +++ 13 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 src/openApi/v3/parser/getMediaType.ts diff --git a/src/client/interfaces/OperationParameter.d.ts b/src/client/interfaces/OperationParameter.d.ts index 403d57e2..77c0da77 100644 --- a/src/client/interfaces/OperationParameter.d.ts +++ b/src/client/interfaces/OperationParameter.d.ts @@ -3,4 +3,5 @@ import type { Model } from './Model'; export interface OperationParameter extends Model { in: 'path' | 'query' | 'header' | 'formData' | 'body' | 'cookie'; prop: string; + mediaType: string | null; } diff --git a/src/openApi/v2/parser/getOperationParameter.ts b/src/openApi/v2/parser/getOperationParameter.ts index de18c71a..2b8ab927 100644 --- a/src/openApi/v2/parser/getOperationParameter.ts +++ b/src/openApi/v2/parser/getOperationParameter.ts @@ -42,6 +42,7 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame enum: [], enums: [], properties: [], + mediaType: null, }; if (parameter.$ref) { diff --git a/src/openApi/v3/parser/getMediaType.ts b/src/openApi/v3/parser/getMediaType.ts new file mode 100644 index 00000000..98840ffc --- /dev/null +++ b/src/openApi/v3/parser/getMediaType.ts @@ -0,0 +1,10 @@ +import type { Dictionary } from '../../../utils/types'; +import type { OpenApi } from '../interfaces/OpenApi'; +import type { OpenApiMediaType } from '../interfaces/OpenApiMediaType'; + +export function getMediaType(openApi: OpenApi, content: Dictionary): string | null { + return ( + Object.keys(content).find(key => ['application/json-patch+json', 'application/json', 'text/json', 'text/plain', 'multipart/mixed', 'multipart/related', 'multipart/batch'].includes(key)) || + null + ); +} diff --git a/src/openApi/v3/parser/getOperationParameter.ts b/src/openApi/v3/parser/getOperationParameter.ts index b126fc9b..27976edc 100644 --- a/src/openApi/v3/parser/getOperationParameter.ts +++ b/src/openApi/v3/parser/getOperationParameter.ts @@ -27,6 +27,7 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame enum: [], enums: [], properties: [], + mediaType: null, }; if (parameter.$ref) { diff --git a/src/openApi/v3/parser/getOperationRequestBody.ts b/src/openApi/v3/parser/getOperationRequestBody.ts index 321c68e6..a42dbae7 100644 --- a/src/openApi/v3/parser/getOperationRequestBody.ts +++ b/src/openApi/v3/parser/getOperationRequestBody.ts @@ -4,6 +4,7 @@ import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiRequestBody } from '../interfaces/OpenApiRequestBody'; import { getComment } from './getComment'; import { getContent } from './getContent'; +import { getMediaType } from './getMediaType'; import { getModel } from './getModel'; import { getType } from './getType'; @@ -27,11 +28,14 @@ export function getOperationRequestBody(openApi: OpenApi, parameter: OpenApiRequ enum: [], enums: [], properties: [], + mediaType: null, }; if (parameter.content) { const schema = getContent(openApi, parameter.content); + const mediaType = getMediaType(openApi, parameter.content); if (schema) { + requestBody.mediaType = mediaType; if (schema?.$ref) { const model = getType(schema.$ref); requestBody.export = 'reference'; diff --git a/src/templates/core/ApiRequestOptions.hbs b/src/templates/core/ApiRequestOptions.hbs index dc33aac8..1419dab0 100644 --- a/src/templates/core/ApiRequestOptions.hbs +++ b/src/templates/core/ApiRequestOptions.hbs @@ -8,6 +8,7 @@ export type ApiRequestOptions = { readonly query?: Record; readonly formData?: Record; readonly body?: any; + readonly bodyMediaType?: string; readonly responseHeader?: string; readonly errors?: Record; } diff --git a/src/templates/core/fetch/getHeaders.hbs b/src/templates/core/fetch/getHeaders.hbs index 9b35a8b5..b4e6d1b2 100644 --- a/src/templates/core/fetch/getHeaders.hbs +++ b/src/templates/core/fetch/getHeaders.hbs @@ -20,12 +20,16 @@ async function getHeaders(options: ApiRequestOptions): Promise { } if (options.body) { - if (isBlob(options.body)) { - headers.append('Content-Type', options.body.type || 'application/octet-stream'); - } else if (isString(options.body)) { - headers.append('Content-Type', 'text/plain'); + if (options.bodyMediaType) { + headers.append('Content-Type', options.bodyMediaType); } else { - headers.append('Content-Type', 'application/json'); + if (isBlob(options.body)) { + headers.append('Content-Type', options.body.type || 'application/octet-stream'); + } else if (isString(options.body)) { + headers.append('Content-Type', 'text/plain'); + } else { + headers.append('Content-Type', 'application/json'); + } } } return headers; diff --git a/src/templates/core/fetch/getRequestBody.hbs b/src/templates/core/fetch/getRequestBody.hbs index 09df2d0b..97b148eb 100644 --- a/src/templates/core/fetch/getRequestBody.hbs +++ b/src/templates/core/fetch/getRequestBody.hbs @@ -3,7 +3,9 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { return getFormData(options.formData); } if (options.body) { - if (isString(options.body) || isBlob(options.body)) { + if (options.bodyMediaType.includes('/json')) { + return JSON.stringify(options.body) + } else if (isString(options.body) || isBlob(options.body)) { return options.body; } else { return JSON.stringify(options.body); diff --git a/src/templates/core/node/getHeaders.hbs b/src/templates/core/node/getHeaders.hbs index 1052e40c..57021103 100644 --- a/src/templates/core/node/getHeaders.hbs +++ b/src/templates/core/node/getHeaders.hbs @@ -20,12 +20,16 @@ async function getHeaders(options: ApiRequestOptions): Promise { } if (options.body) { - if (isBinary(options.body)) { - headers.append('Content-Type', 'application/octet-stream'); - } else if (isString(options.body)) { - headers.append('Content-Type', 'text/plain'); + if (options.bodyMediaType) { + headers.append('Content-Type', options.bodyMediaType); } else { - headers.append('Content-Type', 'application/json'); + if (isBinary(options.body)) { + headers.append('Content-Type', 'application/octet-stream'); + } else if (isString(options.body)) { + headers.append('Content-Type', 'text/plain'); + } else { + headers.append('Content-Type', 'application/json'); + } } } return headers; diff --git a/src/templates/core/node/getRequestBody.hbs b/src/templates/core/node/getRequestBody.hbs index 0977770c..97b148eb 100644 --- a/src/templates/core/node/getRequestBody.hbs +++ b/src/templates/core/node/getRequestBody.hbs @@ -3,7 +3,9 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { return getFormData(options.formData); } if (options.body) { - if (isString(options.body) || isBinary(options.body)) { + if (options.bodyMediaType.includes('/json')) { + return JSON.stringify(options.body) + } else if (isString(options.body) || isBlob(options.body)) { return options.body; } else { return JSON.stringify(options.body); diff --git a/src/templates/core/xhr/getHeaders.hbs b/src/templates/core/xhr/getHeaders.hbs index 9b35a8b5..b4e6d1b2 100644 --- a/src/templates/core/xhr/getHeaders.hbs +++ b/src/templates/core/xhr/getHeaders.hbs @@ -20,12 +20,16 @@ async function getHeaders(options: ApiRequestOptions): Promise { } if (options.body) { - if (isBlob(options.body)) { - headers.append('Content-Type', options.body.type || 'application/octet-stream'); - } else if (isString(options.body)) { - headers.append('Content-Type', 'text/plain'); + if (options.bodyMediaType) { + headers.append('Content-Type', options.bodyMediaType); } else { - headers.append('Content-Type', 'application/json'); + if (isBlob(options.body)) { + headers.append('Content-Type', options.body.type || 'application/octet-stream'); + } else if (isString(options.body)) { + headers.append('Content-Type', 'text/plain'); + } else { + headers.append('Content-Type', 'application/json'); + } } } return headers; diff --git a/src/templates/core/xhr/getRequestBody.hbs b/src/templates/core/xhr/getRequestBody.hbs index 33ec6249..19d6bc51 100644 --- a/src/templates/core/xhr/getRequestBody.hbs +++ b/src/templates/core/xhr/getRequestBody.hbs @@ -3,7 +3,9 @@ function getRequestBody(options: ApiRequestOptions): any { return getFormData(options.formData); } if (options.body) { - if (isString(options.body) || isBlob(options.body)) { + if (options.bodyMediaType.includes('/json')) { + return JSON.stringify(options.body) + } else if (isString(options.body) || isBlob(options.body)) { return options.body; } else { return JSON.stringify(options.body); diff --git a/src/templates/exportService.hbs b/src/templates/exportService.hbs index 315640d9..6e29af60 100644 --- a/src/templates/exportService.hbs +++ b/src/templates/exportService.hbs @@ -69,6 +69,9 @@ export class {{{name}}} { {{/if}} {{#if parametersBody}} body: {{{parametersBody.name}}}, + {{#if parametersBody.mediaType}} + bodyMediaType: '{{{parametersBody.mediaType}}}', + {{/if}} {{/if}} {{#if responseHeader}} responseHeader: '{{{responseHeader}}}', From ea7f26b0e9ee76752c9ae4e1b7235f3384d59c21 Mon Sep 17 00:00:00 2001 From: Maarten Van Hoof Date: Wed, 7 Apr 2021 15:08:34 +0200 Subject: [PATCH 2/3] fix(getRequestBody): options.bodyMediaType can be undefined --- src/templates/core/fetch/getRequestBody.hbs | 2 +- src/templates/core/node/getRequestBody.hbs | 4 ++-- src/templates/core/xhr/getRequestBody.hbs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/templates/core/fetch/getRequestBody.hbs b/src/templates/core/fetch/getRequestBody.hbs index 97b148eb..84b3a511 100644 --- a/src/templates/core/fetch/getRequestBody.hbs +++ b/src/templates/core/fetch/getRequestBody.hbs @@ -3,7 +3,7 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { return getFormData(options.formData); } if (options.body) { - if (options.bodyMediaType.includes('/json')) { + if (options.bodyMediaType?.includes('/json')) { return JSON.stringify(options.body) } else if (isString(options.body) || isBlob(options.body)) { return options.body; diff --git a/src/templates/core/node/getRequestBody.hbs b/src/templates/core/node/getRequestBody.hbs index 97b148eb..d66c3500 100644 --- a/src/templates/core/node/getRequestBody.hbs +++ b/src/templates/core/node/getRequestBody.hbs @@ -3,9 +3,9 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { return getFormData(options.formData); } if (options.body) { - if (options.bodyMediaType.includes('/json')) { + if (options.bodyMediaType?.includes('/json')) { return JSON.stringify(options.body) - } else if (isString(options.body) || isBlob(options.body)) { + } else if (isString(options.body) || isBinary(options.body)) { return options.body; } else { return JSON.stringify(options.body); diff --git a/src/templates/core/xhr/getRequestBody.hbs b/src/templates/core/xhr/getRequestBody.hbs index 19d6bc51..a374fb0f 100644 --- a/src/templates/core/xhr/getRequestBody.hbs +++ b/src/templates/core/xhr/getRequestBody.hbs @@ -3,7 +3,7 @@ function getRequestBody(options: ApiRequestOptions): any { return getFormData(options.formData); } if (options.body) { - if (options.bodyMediaType.includes('/json')) { + if (options.bodyMediaType?.includes('/json')) { return JSON.stringify(options.body) } else if (isString(options.body) || isBlob(options.body)) { return options.body; From 968bef7215c8cb3b9767d59940831e4f2ac8e661 Mon Sep 17 00:00:00 2001 From: Maarten Van Hoof Date: Wed, 7 Apr 2021 15:31:00 +0200 Subject: [PATCH 3/3] test(media type): update snapshot --- test/__snapshots__/index.spec.js.snap | 44 +++++++++++++++++++-------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 488b8b79..93f69f28 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -35,6 +35,7 @@ export type ApiRequestOptions = { readonly query?: Record; readonly formData?: Record; readonly body?: any; + readonly bodyMediaType?: string; readonly responseHeader?: string; readonly errors?: Record; }" @@ -180,12 +181,16 @@ async function getHeaders(options: ApiRequestOptions): Promise { } if (options.body) { - if (isBlob(options.body)) { - headers.append('Content-Type', options.body.type || 'application/octet-stream'); - } else if (isString(options.body)) { - headers.append('Content-Type', 'text/plain'); + if (options.bodyMediaType) { + headers.append('Content-Type', options.bodyMediaType); } else { - headers.append('Content-Type', 'application/json'); + if (isBlob(options.body)) { + headers.append('Content-Type', options.body.type || 'application/octet-stream'); + } else if (isString(options.body)) { + headers.append('Content-Type', 'text/plain'); + } else { + headers.append('Content-Type', 'application/json'); + } } } return headers; @@ -196,7 +201,9 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { return getFormData(options.formData); } if (options.body) { - if (isString(options.body) || isBlob(options.body)) { + if (options.bodyMediaType?.includes('/json')) { + return JSON.stringify(options.body) + } else if (isString(options.body) || isBlob(options.body)) { return options.body; } else { return JSON.stringify(options.body); @@ -2383,6 +2390,7 @@ export type ApiRequestOptions = { readonly query?: Record; readonly formData?: Record; readonly body?: any; + readonly bodyMediaType?: string; readonly responseHeader?: string; readonly errors?: Record; }" @@ -2528,12 +2536,16 @@ async function getHeaders(options: ApiRequestOptions): Promise { } if (options.body) { - if (isBlob(options.body)) { - headers.append('Content-Type', options.body.type || 'application/octet-stream'); - } else if (isString(options.body)) { - headers.append('Content-Type', 'text/plain'); + if (options.bodyMediaType) { + headers.append('Content-Type', options.bodyMediaType); } else { - headers.append('Content-Type', 'application/json'); + if (isBlob(options.body)) { + headers.append('Content-Type', options.body.type || 'application/octet-stream'); + } else if (isString(options.body)) { + headers.append('Content-Type', 'text/plain'); + } else { + headers.append('Content-Type', 'application/json'); + } } } return headers; @@ -2544,7 +2556,9 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { return getFormData(options.formData); } if (options.body) { - if (isString(options.body) || isBlob(options.body)) { + if (options.bodyMediaType?.includes('/json')) { + return JSON.stringify(options.body) + } else if (isString(options.body) || isBlob(options.body)) { return options.body; } else { return JSON.stringify(options.body); @@ -4481,6 +4495,7 @@ export class ComplexService { method: 'PUT', path: \`/api/v\${OpenAPI.VERSION}/complex/\${id}\`, body: requestBody, + bodyMediaType: 'application/json-patch+json', }); return result.body; } @@ -4777,6 +4792,7 @@ export class ParametersService { 'parameterForm': parameterForm, }, body: requestBody, + bodyMediaType: 'application/json', }); return result.body; } @@ -4821,6 +4837,7 @@ export class ParametersService { 'parameter_form': parameterForm, }, body: requestBody, + bodyMediaType: 'application/json', }); return result.body; } @@ -4841,6 +4858,7 @@ export class ParametersService { 'parameter': parameter, }, body: requestBody, + bodyMediaType: 'application/json', }); return result.body; } @@ -4861,6 +4879,7 @@ export class ParametersService { 'parameter': parameter, }, body: requestBody, + bodyMediaType: 'application/json', }); return result.body; } @@ -4889,6 +4908,7 @@ export class RequestBodyService { method: 'POST', path: \`/api/v\${OpenAPI.VERSION}/requestBody/\`, body: requestBody, + bodyMediaType: 'application/json', }); return result.body; }