Skip to content

Commit dc41550

Browse files
authored
[typescript-fetch] Add option to exclude RequestOpts from API interfaces (#23181)
* [typescript-fetch] Add withRequestOptsInInterface option to hide RequestOpts from API interfaces The *RequestOpts methods are implementation details that build request options before sending the fetch call. Most consumers using the API interfaces don't need these methods exposed in the contract. Add a new `withRequestOptsInInterface` boolean option (default: true for backward compatibility) that controls whether *RequestOpts methods appear in the generated API interface declarations. When set to false, the methods remain as public methods on the class but are excluded from the interface. * Fix test: scope RequestOpts assertion to interface section The previous test used indexOf("}") to find the interface end, which matched the } inside @throws {RequiredError} JSDoc instead of the actual closing brace. Use the class declaration position as the boundary instead. * Fix forbiddenapis violation: use explicit UTF-8 charset Replace new String(byte[]) with new String(byte[], StandardCharsets.UTF_8) to satisfy the forbiddenapis Maven plugin check. * Add withRequestOptsInInterface to options test and regenerate docs
1 parent a7eedd9 commit dc41550

5 files changed

Lines changed: 70 additions & 0 deletions

File tree

docs/generators/typescript-fetch.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
4747
|useSquareBracketsInArrayNames|Setting this property to true will add brackets to array attribute names, e.g. my_values[].| |false|
4848
|validationAttributes|Setting this property to true will generate the validation attributes of model properties.| |false|
4949
|withInterfaces|Setting this property to true will generate interfaces next to the default class implementations.| |false|
50+
|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|
5051
|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|
5152

5253
## IMPORT MAPPING

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,15 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
6161
public static final String PASCAL_CASE = "PascalCase";
6262
public static final String USE_SQUARE_BRACKETS_IN_ARRAY_NAMES = "useSquareBracketsInArrayNames";
6363
public static final String VALIDATION_ATTRIBUTES = "validationAttributes";
64+
public static final String WITH_REQUEST_OPTS_IN_INTERFACE = "withRequestOptsInInterface";
6465

6566
@Getter @Setter
6667
protected String npmRepository = null;
6768
@Getter @Setter
6869
protected String importFileExtension = "";
6970
private boolean useSingleRequestParameter = true;
7071
private boolean prefixParameterInterfaces = false;
72+
private boolean withRequestOptsInInterface = true;
7173
protected boolean addedApiIndex = false;
7274
protected boolean addedModelIndex = false;
7375
protected boolean withoutRuntimeChecks = false;
@@ -130,6 +132,7 @@ public TypeScriptFetchClientCodegen() {
130132
this.cliOptions.add(new CliOption(FILE_NAMING, "Naming convention for the output files: 'PascalCase', 'camelCase', 'kebab-case'.").defaultValue(this.fileNaming));
131133
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()));
132134
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()));
135+
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()));
133136
}
134137

135138
@Override
@@ -273,6 +276,11 @@ public void processOpts() {
273276
}
274277
writePropertyBack(PREFIX_PARAMETER_INTERFACES, getPrefixParameterInterfaces());
275278

279+
if (additionalProperties.containsKey(WITH_REQUEST_OPTS_IN_INTERFACE)) {
280+
this.setWithRequestOptsInInterface(convertPropertyToBoolean(WITH_REQUEST_OPTS_IN_INTERFACE));
281+
}
282+
writePropertyBack(WITH_REQUEST_OPTS_IN_INTERFACE, getWithRequestOptsInInterface());
283+
276284
if (additionalProperties.containsKey(NPM_NAME)) {
277285
addNpmPackageGeneration();
278286
}
@@ -1084,6 +1092,14 @@ private void setPrefixParameterInterfaces(boolean prefixParameterInterfaces) {
10841092
this.prefixParameterInterfaces = prefixParameterInterfaces;
10851093
}
10861094

1095+
private boolean getWithRequestOptsInInterface() {
1096+
return withRequestOptsInInterface;
1097+
}
1098+
1099+
private void setWithRequestOptsInInterface(boolean withRequestOptsInInterface) {
1100+
this.withRequestOptsInInterface = withRequestOptsInInterface;
1101+
}
1102+
10871103
private static boolean itemsAreUniqueId(CodegenProperty items) {
10881104
if (items != null && items.items != null) {
10891105
return itemsAreUniqueId(items.items);

modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export interface {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterIn
4242
*/
4343
export interface {{classname}}Interface {
4444
{{#operation}}
45+
{{#withRequestOptsInInterface}}
4546
/**
4647
* Creates request options for {{nickname}} without sending the request
4748
{{#allParams}}
@@ -55,6 +56,7 @@ export interface {{classname}}Interface {
5556
*/
5657
{{nickname}}RequestOpts({{#allParams.0}}requestParameters: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}Request{{/allParams.0}}): Promise<runtime.RequestOpts>;
5758

59+
{{/withRequestOptsInInterface}}
5860
/**
5961
* {{&notes}}
6062
{{#summary}}

modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public Map<String, String> createOptions() {
5353
.put(TypeScriptFetchClientCodegen.STRING_ENUMS, STRING_ENUMS)
5454
.put(TypeScriptFetchClientCodegen.USE_SQUARE_BRACKETS_IN_ARRAY_NAMES, Boolean.FALSE.toString())
5555
.put(TypeScriptFetchClientCodegen.VALIDATION_ATTRIBUTES, Boolean.FALSE.toString())
56+
.put(TypeScriptFetchClientCodegen.WITH_REQUEST_OPTS_IN_INTERFACE, Boolean.TRUE.toString())
5657
.build();
5758
}
5859
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import java.io.File;
2323
import java.io.IOException;
24+
import java.nio.charset.StandardCharsets;
2425
import java.nio.file.Files;
2526
import java.nio.file.Path;
2627
import java.nio.file.Paths;
@@ -458,6 +459,55 @@ public void testValidationAttributesWithWithoutRuntimeChecks() throws IOExceptio
458459
TestUtils.assertFileContains(modelsIndex, "[property: string]:");
459460
}
460461

462+
@Test(description = "Verify withRequestOptsInInterface=true (default) includes RequestOpts in interface")
463+
public void testRequestOptsInInterfaceByDefault() throws IOException {
464+
Map<String, Object> properties = new HashMap<>();
465+
properties.put(TypeScriptFetchClientCodegen.WITH_INTERFACES, true);
466+
467+
File output = generate(properties);
468+
469+
Path apiFile = Paths.get(output + "/apis/PetControllerApi.ts");
470+
TestUtils.assertFileExists(apiFile);
471+
472+
// Read file content and split into interface and class sections
473+
String content = new String(Files.readAllBytes(apiFile), StandardCharsets.UTF_8);
474+
int interfaceStart = content.indexOf("export interface PetControllerApiInterface");
475+
int classStart = content.indexOf("export class PetControllerApi");
476+
String interfaceSection = content.substring(interfaceStart, classStart);
477+
478+
// Interface should contain RequestOpts methods
479+
assertThat(interfaceSection).contains("addPetRequestOpts(");
480+
481+
// Class should also contain RequestOpts methods
482+
String classSection = content.substring(classStart);
483+
assertThat(classSection).contains("async addPetRequestOpts(");
484+
}
485+
486+
@Test(description = "Verify withRequestOptsInInterface=false excludes RequestOpts from interface but keeps them on class")
487+
public void testRequestOptsNotInInterfaceWhenDisabled() throws IOException {
488+
Map<String, Object> properties = new HashMap<>();
489+
properties.put(TypeScriptFetchClientCodegen.WITH_INTERFACES, true);
490+
properties.put(TypeScriptFetchClientCodegen.WITH_REQUEST_OPTS_IN_INTERFACE, false);
491+
492+
File output = generate(properties);
493+
494+
Path apiFile = Paths.get(output + "/apis/PetControllerApi.ts");
495+
TestUtils.assertFileExists(apiFile);
496+
497+
// Read file content and split into interface and class sections
498+
String content = new String(Files.readAllBytes(apiFile), StandardCharsets.UTF_8);
499+
int interfaceStart = content.indexOf("export interface PetControllerApiInterface");
500+
int classStart = content.indexOf("export class PetControllerApi");
501+
String interfaceSection = content.substring(interfaceStart, classStart);
502+
503+
// Interface should NOT contain RequestOpts methods
504+
assertThat(interfaceSection).doesNotContain("RequestOpts");
505+
506+
// Class should still contain RequestOpts methods
507+
String classSection = content.substring(classStart);
508+
assertThat(classSection).contains("async addPetRequestOpts(");
509+
}
510+
461511
private static File generate(
462512
Map<String, Object> properties
463513
) throws IOException {

0 commit comments

Comments
 (0)