diff --git a/.changeset/cuddly-beans-film.md b/.changeset/cuddly-beans-film.md new file mode 100644 index 000000000..82b4e8a27 --- /dev/null +++ b/.changeset/cuddly-beans-film.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": minor +--- + +feat(fetch): detect form data repsonses properly diff --git a/.changeset/metal-boxes-melt.md b/.changeset/metal-boxes-melt.md new file mode 100644 index 000000000..e316901ba --- /dev/null +++ b/.changeset/metal-boxes-melt.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +client(angular/fetch/xhr): detect all application/json or +json as JSON diff --git a/.changeset/ninety-rice-lie.md b/.changeset/ninety-rice-lie.md new file mode 100644 index 000000000..cad2430cc --- /dev/null +++ b/.changeset/ninety-rice-lie.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": minor +--- + +feat(fetch): add application/octet-stream, application/pdf, and application/zip as binary response types diff --git a/src/templates/core/angular/getRequestBody.hbs b/src/templates/core/angular/getRequestBody.hbs index 4ef908685..6b9c0db4d 100644 --- a/src/templates/core/angular/getRequestBody.hbs +++ b/src/templates/core/angular/getRequestBody.hbs @@ -1,6 +1,6 @@ export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body) } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; diff --git a/src/templates/core/fetch/getRequestBody.hbs b/src/templates/core/fetch/getRequestBody.hbs index a916e70db..b8bfed7ba 100644 --- a/src/templates/core/fetch/getRequestBody.hbs +++ b/src/templates/core/fetch/getRequestBody.hbs @@ -1,6 +1,6 @@ export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body) } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; diff --git a/src/templates/core/fetch/getResponseBody.hbs b/src/templates/core/fetch/getResponseBody.hbs index e0279c72d..9d631ad37 100644 --- a/src/templates/core/fetch/getResponseBody.hbs +++ b/src/templates/core/fetch/getResponseBody.hbs @@ -3,15 +3,14 @@ export const getResponseBody = async (response: Response): Promise => { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const binaryTypes = ['audio/', 'image/', 'video/']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - const isBinary = binaryTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + const binaryTypes = ['application/octet-stream', 'application/pdf', 'application/zip', 'audio/', 'image/', 'video/']; + if (contentType.includes('application/json') || contentType.includes('+json')) { return await response.json(); - } else if (isBinary) { + } else if (binaryTypes.some(type => contentType.includes(type))) { return await response.blob(); - } else { + } else if (contentType.includes('multipart/form-data')) { + return await response.formData(); + } else if (contentType.includes('text/')) { return await response.text(); } } diff --git a/src/templates/core/xhr/getRequestBody.hbs b/src/templates/core/xhr/getRequestBody.hbs index a916e70db..b8bfed7ba 100644 --- a/src/templates/core/xhr/getRequestBody.hbs +++ b/src/templates/core/xhr/getRequestBody.hbs @@ -1,6 +1,6 @@ export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body) } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; diff --git a/src/templates/core/xhr/getResponseBody.hbs b/src/templates/core/xhr/getResponseBody.hbs index c7817fe18..0bd9d354e 100644 --- a/src/templates/core/xhr/getResponseBody.hbs +++ b/src/templates/core/xhr/getResponseBody.hbs @@ -3,9 +3,7 @@ export const getResponseBody = (xhr: XMLHttpRequest): unknown => { try { const contentType = xhr.getResponseHeader('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + if (contentType.includes('application/json') || contentType.includes('+json')) { return JSON.parse(xhr.responseText); } else { return xhr.responseText; diff --git a/test/__snapshots__/v2/core/request.ts.snap b/test/__snapshots__/v2/core/request.ts.snap index b7e9802f1..bee3d3694 100644 --- a/test/__snapshots__/v2/core/request.ts.snap +++ b/test/__snapshots__/v2/core/request.ts.snap @@ -156,7 +156,7 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; @@ -213,15 +213,21 @@ export const getResponseBody = async (response: Response): Promise => { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const binaryTypes = ['audio/', 'image/', 'video/']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - const isBinary = binaryTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + const binaryTypes = [ + 'application/octet-stream', + 'application/pdf', + 'application/zip', + 'audio/', + 'image/', + 'video/', + ]; + if (contentType.includes('application/json') || contentType.includes('+json')) { return await response.json(); - } else if (isBinary) { + } else if (binaryTypes.some(type => contentType.includes(type))) { return await response.blob(); - } else { + } else if (contentType.includes('multipart/form-data')) { + return await response.formData(); + } else if (contentType.includes('text/')) { return await response.text(); } } diff --git a/test/__snapshots__/v3/core/request.ts.snap b/test/__snapshots__/v3/core/request.ts.snap index b7e9802f1..bee3d3694 100644 --- a/test/__snapshots__/v3/core/request.ts.snap +++ b/test/__snapshots__/v3/core/request.ts.snap @@ -156,7 +156,7 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; @@ -213,15 +213,21 @@ export const getResponseBody = async (response: Response): Promise => { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const binaryTypes = ['audio/', 'image/', 'video/']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - const isBinary = binaryTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + const binaryTypes = [ + 'application/octet-stream', + 'application/pdf', + 'application/zip', + 'audio/', + 'image/', + 'video/', + ]; + if (contentType.includes('application/json') || contentType.includes('+json')) { return await response.json(); - } else if (isBinary) { + } else if (binaryTypes.some(type => contentType.includes(type))) { return await response.blob(); - } else { + } else if (contentType.includes('multipart/form-data')) { + return await response.formData(); + } else if (contentType.includes('text/')) { return await response.text(); } } diff --git a/test/__snapshots__/v3_angular/core/request.ts.snap b/test/__snapshots__/v3_angular/core/request.ts.snap index f2feb7408..fc2a49e2d 100644 --- a/test/__snapshots__/v3_angular/core/request.ts.snap +++ b/test/__snapshots__/v3_angular/core/request.ts.snap @@ -162,7 +162,7 @@ export const getHeaders = (config: OpenAPIConfig, options: ApiRequestOptions): O export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; diff --git a/test/__snapshots__/v3_client/core/request.ts.snap b/test/__snapshots__/v3_client/core/request.ts.snap index b7e9802f1..bee3d3694 100644 --- a/test/__snapshots__/v3_client/core/request.ts.snap +++ b/test/__snapshots__/v3_client/core/request.ts.snap @@ -156,7 +156,7 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; @@ -213,15 +213,21 @@ export const getResponseBody = async (response: Response): Promise => { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const binaryTypes = ['audio/', 'image/', 'video/']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - const isBinary = binaryTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + const binaryTypes = [ + 'application/octet-stream', + 'application/pdf', + 'application/zip', + 'audio/', + 'image/', + 'video/', + ]; + if (contentType.includes('application/json') || contentType.includes('+json')) { return await response.json(); - } else if (isBinary) { + } else if (binaryTypes.some(type => contentType.includes(type))) { return await response.blob(); - } else { + } else if (contentType.includes('multipart/form-data')) { + return await response.formData(); + } else if (contentType.includes('text/')) { return await response.text(); } } diff --git a/test/__snapshots__/v3_enums_typescript/core/request.ts.snap b/test/__snapshots__/v3_enums_typescript/core/request.ts.snap index b7e9802f1..bee3d3694 100644 --- a/test/__snapshots__/v3_enums_typescript/core/request.ts.snap +++ b/test/__snapshots__/v3_enums_typescript/core/request.ts.snap @@ -156,7 +156,7 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; @@ -213,15 +213,21 @@ export const getResponseBody = async (response: Response): Promise => { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const binaryTypes = ['audio/', 'image/', 'video/']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - const isBinary = binaryTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + const binaryTypes = [ + 'application/octet-stream', + 'application/pdf', + 'application/zip', + 'audio/', + 'image/', + 'video/', + ]; + if (contentType.includes('application/json') || contentType.includes('+json')) { return await response.json(); - } else if (isBinary) { + } else if (binaryTypes.some(type => contentType.includes(type))) { return await response.blob(); - } else { + } else if (contentType.includes('multipart/form-data')) { + return await response.formData(); + } else if (contentType.includes('text/')) { return await response.text(); } } diff --git a/test/__snapshots__/v3_experimental/core/request.ts.snap b/test/__snapshots__/v3_experimental/core/request.ts.snap index b7e9802f1..bee3d3694 100644 --- a/test/__snapshots__/v3_experimental/core/request.ts.snap +++ b/test/__snapshots__/v3_experimental/core/request.ts.snap @@ -156,7 +156,7 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; @@ -213,15 +213,21 @@ export const getResponseBody = async (response: Response): Promise => { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const binaryTypes = ['audio/', 'image/', 'video/']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - const isBinary = binaryTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + const binaryTypes = [ + 'application/octet-stream', + 'application/pdf', + 'application/zip', + 'audio/', + 'image/', + 'video/', + ]; + if (contentType.includes('application/json') || contentType.includes('+json')) { return await response.json(); - } else if (isBinary) { + } else if (binaryTypes.some(type => contentType.includes(type))) { return await response.blob(); - } else { + } else if (contentType.includes('multipart/form-data')) { + return await response.formData(); + } else if (contentType.includes('text/')) { return await response.text(); } } diff --git a/test/__snapshots__/v3_node/core/request.ts.snap b/test/__snapshots__/v3_node/core/request.ts.snap index 09084667e..b48a33dd9 100644 --- a/test/__snapshots__/v3_node/core/request.ts.snap +++ b/test/__snapshots__/v3_node/core/request.ts.snap @@ -159,7 +159,7 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; @@ -212,15 +212,21 @@ export const getResponseBody = async (response: Response): Promise => { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const binaryTypes = ['audio/', 'image/', 'video/']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - const isBinary = binaryTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + const binaryTypes = [ + 'application/octet-stream', + 'application/pdf', + 'application/zip', + 'audio/', + 'image/', + 'video/', + ]; + if (contentType.includes('application/json') || contentType.includes('+json')) { return await response.json(); - } else if (isBinary) { + } else if (binaryTypes.some(type => contentType.includes(type))) { return await response.blob(); - } else { + } else if (contentType.includes('multipart/form-data')) { + return await response.formData(); + } else if (contentType.includes('text/')) { return await response.text(); } } diff --git a/test/__snapshots__/v3_options/core/request.ts.snap b/test/__snapshots__/v3_options/core/request.ts.snap index b7e9802f1..bee3d3694 100644 --- a/test/__snapshots__/v3_options/core/request.ts.snap +++ b/test/__snapshots__/v3_options/core/request.ts.snap @@ -156,7 +156,7 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; @@ -213,15 +213,21 @@ export const getResponseBody = async (response: Response): Promise => { try { const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const binaryTypes = ['audio/', 'image/', 'video/']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - const isBinary = binaryTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + const binaryTypes = [ + 'application/octet-stream', + 'application/pdf', + 'application/zip', + 'audio/', + 'image/', + 'video/', + ]; + if (contentType.includes('application/json') || contentType.includes('+json')) { return await response.json(); - } else if (isBinary) { + } else if (binaryTypes.some(type => contentType.includes(type))) { return await response.blob(); - } else { + } else if (contentType.includes('multipart/form-data')) { + return await response.formData(); + } else if (contentType.includes('text/')) { return await response.text(); } } diff --git a/test/__snapshots__/v3_xhr/core/request.ts.snap b/test/__snapshots__/v3_xhr/core/request.ts.snap index c24d41264..a13dfd84e 100644 --- a/test/__snapshots__/v3_xhr/core/request.ts.snap +++ b/test/__snapshots__/v3_xhr/core/request.ts.snap @@ -160,7 +160,7 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): unknown => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { + if (options.mediaType?.includes('application/json') || options.mediaType?.includes('+json')) { return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; @@ -218,9 +218,7 @@ export const getResponseBody = (xhr: XMLHttpRequest): unknown => { try { const contentType = xhr.getResponseHeader('Content-Type'); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json']; - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); - if (isJSON) { + if (contentType.includes('application/json') || contentType.includes('+json')) { return JSON.parse(xhr.responseText); } else { return xhr.responseText;