Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(fetch): take param serializer setting into account #1795

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/src/pages/reference/configuration/output.md
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,8 @@ Use this property to add a custom params serializer to all requests that use que

If you provide an object you can also add a default property to use an export default function.

If this is not specified, params are serialized as per `axios` default when using `axios`, or by using `URLSearchParams` when using `fetch`.

Example:

```js
Expand Down Expand Up @@ -1759,9 +1761,10 @@ export const customParamsSerializerFn = (

Type: `Object`

Use this property to add a default params serializer. Current options are: `qs`.
Use this property to decide how params are serialized. This is only taken into account when `paramsSerializer` is not defined.
Currently, only `qs` is the available option. Read more about `qs` and it's settings [here](https://www.npmjs.com/package/qs).

All options are then passed to the chosen serializer.
If this is not specified, params are serialized as per `axios` default when using `axios`, or by using `URLSearchParams` when using `fetch`.

Example:

Expand Down
56 changes: 44 additions & 12 deletions packages/fetch/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
generateBodyOptions,
isObject,
resolveRef,
GeneratorDependency,
ClientDependenciesBuilder,
} from '@orval/core';
import {
PathItemObject,
Expand Down Expand Up @@ -86,23 +88,30 @@ export const generateRequestFunction = (
normalizedParams.append(key, value === null ? 'null' : value.toString())
}`;

const getUrlFnImplementation = `export const ${getUrlFnName} = (${getUrlFnProps}) => {
${
queryParams
? ` const normalizedParams = new URLSearchParams();
const queryImplementation = queryParams
? override.paramsSerializer
? `const normalizedParams = ${override.paramsSerializer.name}(params);`
: override.paramsSerializerOptions?.qs
? `const normalizedParams = qs.stringify(params, ${JSON.stringify(
override.paramsSerializerOptions!.qs,
)});`
: `const normalizedParams = new URLSearchParams();

Object.entries(params || {}).forEach(([key, value]) => {
${explodeArrayImplementation}
${!isExplodeParametersOnly ? nomalParamsImplementation : ''}
});`
: ''
}
: '';
const returnQueryImplementation = queryParams
? override.paramsSerializer || override.paramsSerializerOptions?.qs
? `return normalizedParams ? \`${route}${'?${normalizedParams}'}\` : \`${route}\``
: `return normalizedParams.size ? \`${route}${'?${normalizedParams.toString()}'}\` : \`${route}\``
: `return \`${route}\``;

${
queryParams
? `return normalizedParams.size ? \`${route}${'?${normalizedParams.toString()}'}\` : \`${route}\``
: `return \`${route}\``
}
const getUrlFnImplementation = `export const ${getUrlFnName} = (${getUrlFnProps}) => {
${queryImplementation}

${returnQueryImplementation}
}\n`;

const isNdJson = response.contentTypes.some(
Expand Down Expand Up @@ -235,9 +244,32 @@ export const generateClient: ClientBuilder = (verbOptions, options) => {
};
};

const PARAMS_SERIALIZER_DEPENDENCIES: GeneratorDependency[] = [
{
exports: [
{
name: 'qs',
default: true,
values: true,
syntheticDefaultImport: true,
},
],
dependency: 'qs',
},
];

const getFetchDependencies: ClientDependenciesBuilder = (
_: boolean,
hasParamsSerializerOptions: boolean,
) => {
return [
...(hasParamsSerializerOptions ? PARAMS_SERIALIZER_DEPENDENCIES : []),
];
};

const fetchClientBuilder: ClientGeneratorsBuilder = {
client: generateClient,
dependencies: () => [],
dependencies: getFetchDependencies,
};

export const builder = () => () => fetchClientBuilder;
Expand Down
31 changes: 31 additions & 0 deletions tests/configs/default.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,35 @@ export default defineConfig({
target: '../specifications/petstore.yaml',
},
},
paramsSerializer: {
output: {
target: '../generated/default/params-serializer/endpoints.ts',
schemas: '../generated/default/params-serializer/model',
override: {
paramsSerializer: {
path: '../mutators/params-serializer.ts',
name: 'customParamsSerializer',
},
},
},
input: {
target: '../specifications/petstore.yaml',
},
},
paramsSerializerOptions: {
output: {
target: '../generated/default/params-serializer-options/endpoints.ts',
schemas: '../generated/default/params-serializer-options/model',
override: {
paramsSerializerOptions: {
qs: {
arrayFormat: 'repeat',
},
},
},
},
input: {
target: '../specifications/petstore.yaml',
},
},
});
33 changes: 33 additions & 0 deletions tests/configs/fetch.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,39 @@ export default defineConfig({
target: '../specifications/parameters.yaml',
},
},
paramsSerializer: {
output: {
target: '../generated/fetch/params-serializer/endpoints.ts',
schemas: '../generated/fetch/params-serializer/model',
client: 'fetch',
override: {
paramsSerializer: {
path: '../mutators/params-serializer.ts',
name: 'customParamsSerializer',
},
},
},
input: {
target: '../specifications/petstore.yaml',
},
},
paramsSerializerOptions: {
output: {
target: '../generated/fetch/params-serializer-options/endpoints.ts',
schemas: '../generated/fetch/params-serializer-options/model',
client: 'fetch',
override: {
paramsSerializerOptions: {
qs: {
arrayFormat: 'repeat',
},
},
},
},
input: {
target: '../specifications/petstore.yaml',
},
},
importFromSubdirectory: {
output: {
target: '../generated/fetch/importFromSubdirectory/endpoints.ts',
Expand Down
11 changes: 11 additions & 0 deletions tests/mutators/params-serializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const customParamsSerializer = (params: Record<string, any>): string => {
const normalizedParams = new URLSearchParams();

Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? 'null' : value.toString());
}
});

return normalizedParams.toString();
};
2 changes: 2 additions & 0 deletions tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"author": "Victor Bury",
"license": "ISC",
"devDependencies": {
"@types/qs": "^6",
"npm-run-all": "^4.1.5",
"orval": "link:../packages/orval/dist",
"typescript": "5.3.3"
Expand All @@ -37,6 +38,7 @@
"@types/react": "18.3.2",
"axios": "^0.26.1",
"msw": "^2.0.2",
"qs": "^6.13.1",
"react": "^18.3.1",
"swr": "^2.2.4",
"vue": "^3.3.4",
Expand Down
Loading
Loading