Skip to content

Commit

Permalink
fix: infer responseType in SDKs for axios client
Browse files Browse the repository at this point in the history
  • Loading branch information
mrlubos committed Dec 12, 2024
1 parent 2bf1233 commit 4555796
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/fresh-feet-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': patch
---

fix: infer responseType in SDKs for axios client
2 changes: 1 addition & 1 deletion packages/openapi-ts/src/ir/operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const operationPagination = ({

type StatusGroup = '1XX' | '2XX' | '3XX' | '4XX' | '5XX' | 'default';

const statusCodeToGroup = ({
export const statusCodeToGroup = ({
statusCode,
}: {
statusCode: string;
Expand Down
75 changes: 74 additions & 1 deletion packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import type { ObjectValue } from '../../../compiler/types';
import { clientApi, clientModulePath } from '../../../generate/client';
import type { IRContext } from '../../../ir/context';
import type { IROperationObject } from '../../../ir/ir';
import { hasOperationDataRequired } from '../../../ir/operation';
import {
hasOperationDataRequired,
statusCodeToGroup,
} from '../../../ir/operation';
import { escapeComment } from '../../../utils/escape';
import { getServiceName } from '../../../utils/postprocess';
import { irRef } from '../../../utils/ref';
Expand Down Expand Up @@ -74,6 +77,56 @@ export const operationOptionsType = ({

const sdkId = 'sdk';

/**
* Infers `responseType` value from provided response content type. This is
* an adapted version of `getParseAs()` from the Fetch API client.
*
* From Axios documentation:
* `responseType` indicates the type of data that the server will respond with
* options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
* browser only: 'blob'
*/
export const getResponseType = (
contentType: string | null | undefined,
):
| 'arraybuffer'
| 'blob'
| 'document'
| 'json'
| 'stream'
| 'text'
| undefined => {
if (!contentType) {
return;
}

const cleanContent = contentType.split(';')[0].trim();

if (
cleanContent.startsWith('application/json') ||
cleanContent.endsWith('+json')
) {
return 'json';
}

// Axios does not handle form data out of the box
// if (cleanContent === 'multipart/form-data') {
// return 'formData';
// }

if (
['application/', 'audio/', 'image/', 'video/'].some((type) =>
cleanContent.startsWith(type),
)
) {
return 'blob';
}

if (cleanContent.startsWith('text/')) {
return 'text';
}
};

Check warning on line 128 in packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts#L90-L128

Added lines #L90 - L128 were not covered by tests

const operationStatements = ({
context,
operation,
Expand Down Expand Up @@ -173,6 +226,26 @@ const operationStatements = ({
});
}

if (context.config.client.name === '@hey-api/client-axios') {
// try to infer `responseType` option for Axios. We don't need this in
// Fetch API client because it automatically detects the correct response
// during runtime.
for (const statusCode in operation.responses) {
// this doesn't handle default status code for now
if (statusCodeToGroup({ statusCode }) === '2XX') {
const response = operation.responses[statusCode];
const responseType = getResponseType(response?.mediaType);
// json is the default, skip it
if (responseType && responseType !== 'json') {
requestOptions.push({
key: 'responseType',
value: responseType,
});
}
}
}
}

Check warning on line 247 in packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts#L230-L247

Added lines #L230 - L247 were not covered by tests

// TODO: parser - set parseAs to skip inference if every response has the same
// content type. currently impossible because successes do not contain
// header information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export const uploadFile = <ThrowOnError extends boolean = false>(options: Option
export const fileResponse = <ThrowOnError extends boolean = false>(options: Options<FileResponseData, ThrowOnError>) => {
return (options?.client ?? client).get<FileResponseResponse, unknown, ThrowOnError>({
...options,
responseType: 'blob',
url: '/api/v{api-version}/file/{id}'
});
};
Expand Down

0 comments on commit 4555796

Please sign in to comment.