Skip to content
Merged
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
47 changes: 32 additions & 15 deletions packages/rtk-query-codegen-openapi/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ export async function generateApi(
filterEndpoints,
endpointOverrides,
unionUndefined,
encodeParams = false,
encodePathParams = false,
encodeQueryParams = false,
flattenArg = false,
includeDefault = false,
useEnumType = false,
Expand Down Expand Up @@ -398,7 +399,14 @@ export async function generateApi(
type: isQuery ? 'query' : 'mutation',
Response: ResponseTypeName,
QueryArg,
queryFn: generateQueryFn({ operationDefinition, queryArg, isQuery, isFlatArg, encodeParams }),
queryFn: generateQueryFn({
operationDefinition,
queryArg,
isQuery,
isFlatArg,
encodePathParams,
encodeQueryParams,
}),
extraEndpointsProps: isQuery
? generateQueryEndpointProps({ operationDefinition })
: generateMutationEndpointProps({ operationDefinition }),
Expand All @@ -411,13 +419,15 @@ export async function generateApi(
queryArg,
isFlatArg,
isQuery,
encodeParams,
encodePathParams,
encodeQueryParams,
}: {
operationDefinition: OperationDefinition;
queryArg: QueryArgDefinitions;
isFlatArg: boolean;
isQuery: boolean;
encodeParams: boolean;
encodePathParams: boolean;
encodeQueryParams: boolean;
}) {
const { path, verb } = operationDefinition;

Expand All @@ -434,14 +444,21 @@ export async function generateApi(

const properties = parameters.map((param) => {
const value = isFlatArg ? rootObject : accessProperty(rootObject, param.name);
return createPropertyAssignment(
param.originalName,
encodeParams && param.param?.in === 'query'
? factory.createCallExpression(factory.createIdentifier('encodeURIComponent'), undefined, [
factory.createCallExpression(factory.createIdentifier('String'), undefined, [value]),
])
: value
);

const encodedValue =
encodeQueryParams && param.param?.in === 'query'
? factory.createConditionalExpression(
value,
undefined,
factory.createCallExpression(factory.createIdentifier('encodeURIComponent'), undefined, [
factory.createCallExpression(factory.createIdentifier('String'), undefined, [value]),
]),
undefined,
factory.createIdentifier('undefined')
)
: value;

return createPropertyAssignment(param.originalName, encodedValue);
});

return factory.createPropertyAssignment(
Expand All @@ -463,7 +480,7 @@ export async function generateApi(
[
factory.createPropertyAssignment(
factory.createIdentifier('url'),
generatePathExpression(path, pickParams('path'), rootObject, isFlatArg, encodeParams)
generatePathExpression(path, pickParams('path'), rootObject, isFlatArg, encodePathParams)
),
isQuery && verb.toUpperCase() === 'GET'
? undefined
Expand Down Expand Up @@ -511,7 +528,7 @@ function generatePathExpression(
pathParameters: QueryArgDefinition[],
rootObject: ts.Identifier,
isFlatArg: boolean,
encodeParams: boolean
encodePathParams: boolean
) {
const expressions: Array<[string, string]> = [];

Expand All @@ -529,7 +546,7 @@ function generatePathExpression(
factory.createTemplateHead(head),
expressions.map(([prop, literal], index) => {
const value = isFlatArg ? rootObject : accessProperty(rootObject, prop);
const encodedValue = encodeParams
const encodedValue = encodePathParams
? factory.createCallExpression(factory.createIdentifier('encodeURIComponent'), undefined, [
factory.createCallExpression(factory.createIdentifier('String'), undefined, [value]),
])
Expand Down
9 changes: 7 additions & 2 deletions packages/rtk-query-codegen-openapi/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,14 @@ export interface CommonOptions {
tag?: boolean;
/**
* defaults to false
* `true` will add `encodeURIComponent` to the generated query params
* `true` will add `encodeURIComponent` to the generated path parameters
*/
encodeParams?: boolean;
encodePathParams?: boolean;
/**
* defaults to false
* `true` will add `encodeURIComponent` to the generated query parameters
*/
encodeQueryParams?: boolean;
/**
* defaults to false
* `true` will "flatten" the arg so that you can do things like `useGetEntityById(1)` instead of `useGetEntityById({ entityId: 1 })`
Expand Down
69 changes: 57 additions & 12 deletions packages/rtk-query-codegen-openapi/test/generateEndpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,28 +174,28 @@ describe('endpoint overrides', () => {
});
});

describe('option encodeParams', () => {
describe('option encodePathParams', () => {
const config = {
apiFile: './fixtures/emptyApi.ts',
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
encodeParams: true,
encodePathParams: true,
};

it('should encode query parameters', async () => {
it('should encode path parameters', async () => {
const api = await generateEndpoints({
...config,
filterEndpoints: ['findPetsByStatus'],
filterEndpoints: ['getOrderById'],
});
expect(api).toContain('status: encodeURIComponent(String(queryArg.status))');
// eslint-disable-next-line no-template-curly-in-string
expect(api).toContain('`/store/order/${encodeURIComponent(String(queryArg.orderId))}`');
});

it('should encode path parameters', async () => {
it('should not encode query parameters', async () => {
const api = await generateEndpoints({
...config,
filterEndpoints: ['getOrderById'],
filterEndpoints: ['findPetsByStatus'],
});
// eslint-disable-next-line no-template-curly-in-string
expect(api).toContain('`/store/order/${encodeURIComponent(String(queryArg.orderId))}`');
expect(api).toContain('status: queryArg.status');
});

it('should not encode body parameters', async () => {
Expand All @@ -217,18 +217,63 @@ describe('option encodeParams', () => {
expect(api).toContain('`/store/order/${encodeURIComponent(String(queryArg))}`');
});

it('should not encode parameters when encodeParams is false', async () => {
it('should not encode path parameters when encodePathParams is false', async () => {
const api = await generateEndpoints({
...config,
encodeParams: false,
encodePathParams: false,
filterEndpoints: ['findPetsByStatus', 'getOrderById'],
});
expect(api).toContain('status: queryArg.status');
// eslint-disable-next-line no-template-curly-in-string
expect(api).toContain('`/store/order/${queryArg.orderId}`');
});
});

describe('option encodeQueryParams', () => {
const config = {
apiFile: './fixtures/emptyApi.ts',
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
encodeQueryParams: true,
};

it('should conditionally encode query parameters', async () => {
const api = await generateEndpoints({
...config,
filterEndpoints: ['findPetsByStatus'],
});

expect(api).toMatch(
/params:\s*{\s*\n\s*status:\s*queryArg\.status\s*\?\s*encodeURIComponent\(\s*String\(queryArg\.status\)\s*\)\s*:\s*undefined\s*,?\s*\n\s*}/s
);
});

it('should not encode path parameters', async () => {
const api = await generateEndpoints({
...config,
filterEndpoints: ['getOrderById'],
});
// eslint-disable-next-line no-template-curly-in-string
expect(api).toContain('`/store/order/${queryArg.orderId}`');
});

it('should not encode body parameters', async () => {
const api = await generateEndpoints({
...config,
filterEndpoints: ['addPet'],
});
expect(api).toContain('body: queryArg.pet');
expect(api).not.toContain('body: encodeURIComponent(String(queryArg.pet))');
});

it('should not encode query parameters when encodeQueryParams is false', async () => {
const api = await generateEndpoints({
...config,
encodeQueryParams: false,
filterEndpoints: ['findPetsByStatus', 'getOrderById'],
});
expect(api).toContain('status: queryArg.status');
});
});

describe('option flattenArg', () => {
const config = {
apiFile: './fixtures/emptyApi.ts',
Expand Down