diff --git a/docs/generators/typescript-fetch.md b/docs/generators/typescript-fetch.md index 3019201de917..9856b1d021ba 100644 --- a/docs/generators/typescript-fetch.md +++ b/docs/generators/typescript-fetch.md @@ -47,6 +47,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |useSquareBracketsInArrayNames|Setting this property to true will add brackets to array attribute names, e.g. my_values[].| |false| |validationAttributes|Setting this property to true will generate the validation attributes of model properties.| |false| |withInterfaces|Setting this property to true will generate interfaces next to the default class implementations.| |false| +|withRequestOptsInInterface|Setting this property to true will include *RequestOpts methods in the API interface declarations. Set to false to keep them only on the class.| |true| |withoutRuntimeChecks|Setting this property to true will remove any runtime checks on the request and response payloads. Payloads will be casted to their expected types.| |false| ## IMPORT MAPPING diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java index 482c286927c7..e66f40d55342 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java @@ -61,6 +61,7 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege public static final String PASCAL_CASE = "PascalCase"; public static final String USE_SQUARE_BRACKETS_IN_ARRAY_NAMES = "useSquareBracketsInArrayNames"; public static final String VALIDATION_ATTRIBUTES = "validationAttributes"; + public static final String WITH_REQUEST_OPTS_IN_INTERFACE = "withRequestOptsInInterface"; @Getter @Setter protected String npmRepository = null; @@ -68,6 +69,7 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege protected String importFileExtension = ""; private boolean useSingleRequestParameter = true; private boolean prefixParameterInterfaces = false; + private boolean withRequestOptsInInterface = true; protected boolean addedApiIndex = false; protected boolean addedModelIndex = false; protected boolean withoutRuntimeChecks = false; @@ -130,6 +132,7 @@ public TypeScriptFetchClientCodegen() { this.cliOptions.add(new CliOption(FILE_NAMING, "Naming convention for the output files: 'PascalCase', 'camelCase', 'kebab-case'.").defaultValue(this.fileNaming)); this.cliOptions.add(new CliOption(USE_SQUARE_BRACKETS_IN_ARRAY_NAMES, "Setting this property to true will add brackets to array attribute names, e.g. my_values[].", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); this.cliOptions.add(new CliOption(VALIDATION_ATTRIBUTES, "Setting this property to true will generate the validation attributes of model properties.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); + this.cliOptions.add(new CliOption(WITH_REQUEST_OPTS_IN_INTERFACE, "Setting this property to true will include *RequestOpts methods in the API interface declarations. Set to false to keep them only on the class.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.TRUE.toString())); } @Override @@ -273,6 +276,11 @@ public void processOpts() { } writePropertyBack(PREFIX_PARAMETER_INTERFACES, getPrefixParameterInterfaces()); + if (additionalProperties.containsKey(WITH_REQUEST_OPTS_IN_INTERFACE)) { + this.setWithRequestOptsInInterface(convertPropertyToBoolean(WITH_REQUEST_OPTS_IN_INTERFACE)); + } + writePropertyBack(WITH_REQUEST_OPTS_IN_INTERFACE, getWithRequestOptsInInterface()); + if (additionalProperties.containsKey(NPM_NAME)) { addNpmPackageGeneration(); } @@ -1084,6 +1092,14 @@ private void setPrefixParameterInterfaces(boolean prefixParameterInterfaces) { this.prefixParameterInterfaces = prefixParameterInterfaces; } + private boolean getWithRequestOptsInInterface() { + return withRequestOptsInInterface; + } + + private void setWithRequestOptsInInterface(boolean withRequestOptsInInterface) { + this.withRequestOptsInInterface = withRequestOptsInInterface; + } + private static boolean itemsAreUniqueId(CodegenProperty items) { if (items != null && items.items != null) { return itemsAreUniqueId(items.items); diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache index 1e8db2b3c4c3..7815a1bac7b7 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache @@ -42,6 +42,7 @@ export interface {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterIn */ export interface {{classname}}Interface { {{#operation}} + {{#withRequestOptsInInterface}} /** * Creates request options for {{nickname}} without sending the request {{#allParams}} @@ -55,6 +56,7 @@ export interface {{classname}}Interface { */ {{nickname}}RequestOpts({{#allParams.0}}requestParameters: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}Request{{/allParams.0}}): Promise; + {{/withRequestOptsInInterface}} /** * {{¬es}} {{#summary}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java index 146b5a69293c..a6bccce568cb 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java @@ -53,6 +53,7 @@ public Map createOptions() { .put(TypeScriptFetchClientCodegen.STRING_ENUMS, STRING_ENUMS) .put(TypeScriptFetchClientCodegen.USE_SQUARE_BRACKETS_IN_ARRAY_NAMES, Boolean.FALSE.toString()) .put(TypeScriptFetchClientCodegen.VALIDATION_ATTRIBUTES, Boolean.FALSE.toString()) + .put(TypeScriptFetchClientCodegen.WITH_REQUEST_OPTS_IN_INTERFACE, Boolean.TRUE.toString()) .build(); } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java index da8324317640..bb63f62225ea 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -458,6 +459,55 @@ public void testValidationAttributesWithWithoutRuntimeChecks() throws IOExceptio TestUtils.assertFileContains(modelsIndex, "[property: string]:"); } + @Test(description = "Verify withRequestOptsInInterface=true (default) includes RequestOpts in interface") + public void testRequestOptsInInterfaceByDefault() throws IOException { + Map properties = new HashMap<>(); + properties.put(TypeScriptFetchClientCodegen.WITH_INTERFACES, true); + + File output = generate(properties); + + Path apiFile = Paths.get(output + "/apis/PetControllerApi.ts"); + TestUtils.assertFileExists(apiFile); + + // Read file content and split into interface and class sections + String content = new String(Files.readAllBytes(apiFile), StandardCharsets.UTF_8); + int interfaceStart = content.indexOf("export interface PetControllerApiInterface"); + int classStart = content.indexOf("export class PetControllerApi"); + String interfaceSection = content.substring(interfaceStart, classStart); + + // Interface should contain RequestOpts methods + assertThat(interfaceSection).contains("addPetRequestOpts("); + + // Class should also contain RequestOpts methods + String classSection = content.substring(classStart); + assertThat(classSection).contains("async addPetRequestOpts("); + } + + @Test(description = "Verify withRequestOptsInInterface=false excludes RequestOpts from interface but keeps them on class") + public void testRequestOptsNotInInterfaceWhenDisabled() throws IOException { + Map properties = new HashMap<>(); + properties.put(TypeScriptFetchClientCodegen.WITH_INTERFACES, true); + properties.put(TypeScriptFetchClientCodegen.WITH_REQUEST_OPTS_IN_INTERFACE, false); + + File output = generate(properties); + + Path apiFile = Paths.get(output + "/apis/PetControllerApi.ts"); + TestUtils.assertFileExists(apiFile); + + // Read file content and split into interface and class sections + String content = new String(Files.readAllBytes(apiFile), StandardCharsets.UTF_8); + int interfaceStart = content.indexOf("export interface PetControllerApiInterface"); + int classStart = content.indexOf("export class PetControllerApi"); + String interfaceSection = content.substring(interfaceStart, classStart); + + // Interface should NOT contain RequestOpts methods + assertThat(interfaceSection).doesNotContain("RequestOpts"); + + // Class should still contain RequestOpts methods + String classSection = content.substring(classStart); + assertThat(classSection).contains("async addPetRequestOpts("); + } + private static File generate( Map properties ) throws IOException {