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

Codegen: add operation name suffix #3812

Merged
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
1 change: 1 addition & 0 deletions docs/rtk-query/usage/code-generation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ interface SimpleUsage {
apiImport?: string
exportName?: string
argSuffix?: string
operationNameSuffix?: string
responseSuffix?: string
hooks?:
| boolean
Expand Down
7 changes: 4 additions & 3 deletions packages/rtk-query-codegen-openapi/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export async function generateApi(
exportName = 'enhancedApi',
argSuffix = 'ApiArg',
responseSuffix = 'ApiResponse',
operationNameSuffix = '',
hooks = false,
tag = false,
outputFile,
Expand Down Expand Up @@ -271,7 +272,7 @@ export async function generateApi(
registerInterface(
factory.createTypeAliasDeclaration(
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
capitalize(operationName + responseSuffix),
capitalize(operationName + operationNameSuffix + responseSuffix),
undefined,
ResponseType
)
Expand Down Expand Up @@ -356,7 +357,7 @@ export async function generateApi(
registerInterface(
factory.createTypeAliasDeclaration(
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
capitalize(operationName + argSuffix),
capitalize(operationName + operationNameSuffix + argSuffix),
undefined,
queryArgValues.length > 0
? isFlatArg
Expand Down Expand Up @@ -390,7 +391,7 @@ export async function generateApi(
);

return generateEndpointDefinition({
operationName,
operationName: operationNameSuffix ? capitalize(operationName + operationNameSuffix) : operationName,
type: isQuery ? 'query' : 'mutation',
Response: ResponseTypeName,
QueryArg,
Expand Down
4 changes: 4 additions & 0 deletions packages/rtk-query-codegen-openapi/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export interface CommonOptions {
* defaults to "ApiResponse"
*/
responseSuffix?: string;
/**
* defaults to empty
*/
operationNameSuffix?: string;
/**
* defaults to `false`
* `true` will generate hooks for queries and mutations, but no lazyQueries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2524,6 +2524,323 @@ export type ExampleSchemaWrite = {
"
`;

exports[`operation suffixes are applied 1`] = `
"import { api } from "./fixtures/emptyApi";
const injectedRtkApi = api.injectEndpoints({
endpoints: (build) => ({
GetHealthcheckV2: build.query<
GetHealthcheckV2ApiResponse,
GetHealthcheckV2ApiArg
>({
query: () => ({ url: \`/healthcheck\` }),
}),
UpdatePetV2: build.mutation<UpdatePetV2ApiResponse, UpdatePetV2ApiArg>({
query: (queryArg) => ({ url: \`/pet\`, method: "PUT", body: queryArg.pet }),
}),
AddPetV2: build.mutation<AddPetV2ApiResponse, AddPetV2ApiArg>({
query: (queryArg) => ({
url: \`/pet\`,
method: "POST",
body: queryArg.pet,
}),
}),
FindPetsByStatusV2: build.query<
FindPetsByStatusV2ApiResponse,
FindPetsByStatusV2ApiArg
>({
query: (queryArg) => ({
url: \`/pet/findByStatus\`,
params: {
status: queryArg.status,
},
}),
}),
FindPetsByTagsV2: build.query<
FindPetsByTagsV2ApiResponse,
FindPetsByTagsV2ApiArg
>({
query: (queryArg) => ({
url: \`/pet/findByTags\`,
params: {
tags: queryArg.tags,
},
}),
}),
GetPetByIdV2: build.query<GetPetByIdV2ApiResponse, GetPetByIdV2ApiArg>({
query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }),
}),
UpdatePetWithFormV2: build.mutation<
UpdatePetWithFormV2ApiResponse,
UpdatePetWithFormV2ApiArg
>({
query: (queryArg) => ({
url: \`/pet/\${queryArg.petId}\`,
method: "POST",
params: {
name: queryArg.name,
status: queryArg.status,
},
}),
}),
DeletePetV2: build.mutation<DeletePetV2ApiResponse, DeletePetV2ApiArg>({
query: (queryArg) => ({
url: \`/pet/\${queryArg.petId}\`,
method: "DELETE",
headers: {
api_key: queryArg.apiKey,
},
}),
}),
UploadFileV2: build.mutation<UploadFileV2ApiResponse, UploadFileV2ApiArg>({
query: (queryArg) => ({
url: \`/pet/\${queryArg.petId}/uploadImage\`,
method: "POST",
body: queryArg.body,
params: {
additionalMetadata: queryArg.additionalMetadata,
},
}),
}),
GetInventoryV2: build.query<
GetInventoryV2ApiResponse,
GetInventoryV2ApiArg
>({
query: () => ({ url: \`/store/inventory\` }),
}),
PlaceOrderV2: build.mutation<PlaceOrderV2ApiResponse, PlaceOrderV2ApiArg>({
query: (queryArg) => ({
url: \`/store/order\`,
method: "POST",
body: queryArg.order,
}),
}),
GetOrderByIdV2: build.query<
GetOrderByIdV2ApiResponse,
GetOrderByIdV2ApiArg
>({
query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }),
}),
DeleteOrderV2: build.mutation<
DeleteOrderV2ApiResponse,
DeleteOrderV2ApiArg
>({
query: (queryArg) => ({
url: \`/store/order/\${queryArg.orderId}\`,
method: "DELETE",
}),
}),
CreateUserV2: build.mutation<CreateUserV2ApiResponse, CreateUserV2ApiArg>({
query: (queryArg) => ({
url: \`/user\`,
method: "POST",
body: queryArg.user,
}),
}),
CreateUsersWithListInputV2: build.mutation<
CreateUsersWithListInputV2ApiResponse,
CreateUsersWithListInputV2ApiArg
>({
query: (queryArg) => ({
url: \`/user/createWithList\`,
method: "POST",
body: queryArg.body,
}),
}),
LoginUserV2: build.query<LoginUserV2ApiResponse, LoginUserV2ApiArg>({
query: (queryArg) => ({
url: \`/user/login\`,
params: {
username: queryArg.username,
password: queryArg.password,
},
}),
}),
LogoutUserV2: build.query<LogoutUserV2ApiResponse, LogoutUserV2ApiArg>({
query: () => ({ url: \`/user/logout\` }),
}),
GetUserByNameV2: build.query<
GetUserByNameV2ApiResponse,
GetUserByNameV2ApiArg
>({
query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }),
}),
UpdateUserV2: build.mutation<UpdateUserV2ApiResponse, UpdateUserV2ApiArg>({
query: (queryArg) => ({
url: \`/user/\${queryArg.username}\`,
method: "PUT",
body: queryArg.user,
}),
}),
DeleteUserV2: build.mutation<DeleteUserV2ApiResponse, DeleteUserV2ApiArg>({
query: (queryArg) => ({
url: \`/user/\${queryArg.username}\`,
method: "DELETE",
}),
}),
}),
overrideExisting: false,
});
export { injectedRtkApi as enhancedApi };
export type GetHealthcheckV2ApiResponse = /** status 200 OK */ {
message: string;
};
export type GetHealthcheckV2ApiArg = void;
export type UpdatePetV2ApiResponse = /** status 200 Successful operation */ Pet;
export type UpdatePetV2ApiArg = {
/** Update an existent pet in the store */
pet: Pet;
};
export type AddPetV2ApiResponse = /** status 200 Successful operation */ Pet;
export type AddPetV2ApiArg = {
/** Create a new pet in the store */
pet: Pet;
};
export type FindPetsByStatusV2ApiResponse =
/** status 200 successful operation */ Pet[];
export type FindPetsByStatusV2ApiArg = {
/** Status values that need to be considered for filter */
status?: "available" | "pending" | "sold";
};
export type FindPetsByTagsV2ApiResponse =
/** status 200 successful operation */ Pet[];
export type FindPetsByTagsV2ApiArg = {
/** Tags to filter by */
tags?: string[];
};
export type GetPetByIdV2ApiResponse =
/** status 200 successful operation */ Pet;
export type GetPetByIdV2ApiArg = {
/** ID of pet to return */
petId: number;
};
export type UpdatePetWithFormV2ApiResponse = unknown;
export type UpdatePetWithFormV2ApiArg = {
/** ID of pet that needs to be updated */
petId: number;
/** Name of pet that needs to be updated */
name?: string;
/** Status of pet that needs to be updated */
status?: string;
};
export type DeletePetV2ApiResponse = unknown;
export type DeletePetV2ApiArg = {
apiKey?: string;
/** Pet id to delete */
petId: number;
};
export type UploadFileV2ApiResponse =
/** status 200 successful operation */ ApiResponse;
export type UploadFileV2ApiArg = {
/** ID of pet to update */
petId: number;
/** Additional Metadata */
additionalMetadata?: string;
body: Blob;
};
export type GetInventoryV2ApiResponse = /** status 200 successful operation */ {
[key: string]: number;
};
export type GetInventoryV2ApiArg = void;
export type PlaceOrderV2ApiResponse =
/** status 200 successful operation */ Order;
export type PlaceOrderV2ApiArg = {
order: Order;
};
export type GetOrderByIdV2ApiResponse =
/** status 200 successful operation */ Order;
export type GetOrderByIdV2ApiArg = {
/** ID of order that needs to be fetched */
orderId: number;
};
export type DeleteOrderV2ApiResponse = unknown;
export type DeleteOrderV2ApiArg = {
/** ID of the order that needs to be deleted */
orderId: number;
};
export type CreateUserV2ApiResponse =
/** status default successful operation */ User;
export type CreateUserV2ApiArg = {
/** Created user object */
user: User;
};
export type CreateUsersWithListInputV2ApiResponse =
/** status 200 Successful operation */ User;
export type CreateUsersWithListInputV2ApiArg = {
body: User[];
};
export type LoginUserV2ApiResponse =
/** status 200 successful operation */ string;
export type LoginUserV2ApiArg = {
/** The user name for login */
username?: string;
/** The password for login in clear text */
password?: string;
};
export type LogoutUserV2ApiResponse = unknown;
export type LogoutUserV2ApiArg = void;
export type GetUserByNameV2ApiResponse =
/** status 200 successful operation */ User;
export type GetUserByNameV2ApiArg = {
/** The name that needs to be fetched. Use user1 for testing. */
username: string;
};
export type UpdateUserV2ApiResponse = unknown;
export type UpdateUserV2ApiArg = {
/** name that need to be deleted */
username: string;
/** Update an existent user in the store */
user: User;
};
export type DeleteUserV2ApiResponse = unknown;
export type DeleteUserV2ApiArg = {
/** The name that needs to be deleted */
username: string;
};
export type Category = {
id?: number | undefined;
name?: string | undefined;
};
export type Tag = {
id?: number | undefined;
name?: string | undefined;
};
export type Pet = {
id?: number | undefined;
name: string;
category?: Category | undefined;
photoUrls: string[];
tags?: Tag[] | undefined;
/** pet status in the store */
status?: ("available" | "pending" | "sold") | undefined;
};
export type ApiResponse = {
code?: number | undefined;
type?: string | undefined;
message?: string | undefined;
};
export type Order = {
id?: number | undefined;
petId?: number | undefined;
quantity?: number | undefined;
shipDate?: string | undefined;
/** Order Status */
status?: ("placed" | "approved" | "delivered") | undefined;
complete?: boolean | undefined;
};
export type User = {
id?: number | undefined;
username?: string | undefined;
firstName?: string | undefined;
lastName?: string | undefined;
email?: string | undefined;
password?: string | undefined;
phone?: string | undefined;
/** User Status */
userStatus?: number | undefined;
};
"
`;

exports[`query parameters > parameters overridden in swagger should also be overridden in the code 1`] = `
"import { api } from "./fixtures/emptyApi";
const injectedRtkApi = api.injectEndpoints({
Expand Down
12 changes: 12 additions & 0 deletions packages/rtk-query-codegen-openapi/test/generateEndpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,18 @@ test('duplicate parameter names must be prefixed with a path or query prefix', a
expect(api).toMatchSnapshot();
});

test('operation suffixes are applied', async () => {
const api = await generateEndpoints({
unionUndefined: true,
apiFile: './fixtures/emptyApi.ts',
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
operationNameSuffix: 'V2',
});

expect(api).toContain('AddPetV2');
expect(api).toMatchSnapshot();
});

test('apiImport builds correct `import` statement', async () => {
const api = await generateEndpoints({
unionUndefined: true,
Expand Down