From 8a1d0390a77cb919e101ebe083703be8f811531d Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Fri, 19 Sep 2025 22:09:44 +0200 Subject: [PATCH 1/9] Update smoke tests to generate and test using --multiple-interfaces --- test/smoke-tests.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/smoke-tests.ps1 b/test/smoke-tests.ps1 index 3d8f2cd6d..0c7bc6708 100644 --- a/test/smoke-tests.ps1 +++ b/test/smoke-tests.ps1 @@ -166,6 +166,8 @@ function RunTests { GenerateAndBuild -format $format -namespace "$namespace.Disposable" -outputPath "Disposable$outputPath" -args "--disposable" -buildFromSource $buildFromSource -netCore GenerateAndBuild -format $format -namespace "$namespace.MultipleFiles" -args "--multiple-files" -buildFromSource $buildFromSource + GenerateAndBuild -format $format -namespace "$namespace.MultipleInterfacesByEndpoint" -args "--multiple-interfaces ByEndpoint" -buildFromSource $buildFromSource + GenerateAndBuild -format $format -namespace "$namespace.MultipleInterfacesByTag" -args "--multiple-interfaces ByTag" -buildFromSource $buildFromSource GenerateAndBuild -format $format -namespace "$namespace.SeparateContractsFile" -args "--contracts-output GeneratedCode/Contracts --contracts-namespace $namespace.SeparateContractsFile.Contracts" -buildFromSource $buildFromSource GenerateAndBuild -format $format -namespace "$namespace.Cancellation" -outputPath "WithCancellation$outputPath" "--cancellation-tokens" -buildFromSource $buildFromSource GenerateAndBuild -format $format -namespace "$namespace.Internal" -outputPath "Internal$outputPath" -args "--internal" -buildFromSource $buildFromSource From a3c7a6855e0fe325e273a2fd0318d4185ca1779b Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Fri, 19 Sep 2025 22:48:03 +0200 Subject: [PATCH 2/9] Update smoke-tests.yml triggers --- .github/workflows/smoke-tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/smoke-tests.yml b/.github/workflows/smoke-tests.yml index 24261ab18..5bab9a24c 100644 --- a/.github/workflows/smoke-tests.yml +++ b/.github/workflows/smoke-tests.yml @@ -16,8 +16,6 @@ on: - "!.github/workflows/template-url.yml" - "!.github/workflows/smoke-tests.yml" - "!test/smoke-tests.ps1" - branches: - - "main" pull_request: paths-ignore: - "**/*" @@ -32,7 +30,7 @@ on: - "!.github/workflows/smoke-tests.yml" - "!test/**/*" branches: - - "*" + - "main" jobs: From 66e70322d885b52856cef7587931f97a28bb0174 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Fri, 19 Sep 2025 23:02:06 +0200 Subject: [PATCH 3/9] Fix build error --- src/Refitter.Tests/Examples/OpenApiUrlTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Refitter.Tests/Examples/OpenApiUrlTests.cs b/src/Refitter.Tests/Examples/OpenApiUrlTests.cs index 6e030987c..10713f1e0 100644 --- a/src/Refitter.Tests/Examples/OpenApiUrlTests.cs +++ b/src/Refitter.Tests/Examples/OpenApiUrlTests.cs @@ -45,5 +45,5 @@ public async Task Can_Build_Generated_Code_From_OpenApi_v3_Url_Yaml(string url) .Should() .BeTrue(url); } -#endif } +#endif From f8315a568611d70eb906b0f90d725c05d6bbfc19 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 20 Sep 2025 00:11:01 +0200 Subject: [PATCH 4/9] Revert changes to smoke-tests.ps1 --- test/smoke-tests.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/smoke-tests.ps1 b/test/smoke-tests.ps1 index 0c7bc6708..3d8f2cd6d 100644 --- a/test/smoke-tests.ps1 +++ b/test/smoke-tests.ps1 @@ -166,8 +166,6 @@ function RunTests { GenerateAndBuild -format $format -namespace "$namespace.Disposable" -outputPath "Disposable$outputPath" -args "--disposable" -buildFromSource $buildFromSource -netCore GenerateAndBuild -format $format -namespace "$namespace.MultipleFiles" -args "--multiple-files" -buildFromSource $buildFromSource - GenerateAndBuild -format $format -namespace "$namespace.MultipleInterfacesByEndpoint" -args "--multiple-interfaces ByEndpoint" -buildFromSource $buildFromSource - GenerateAndBuild -format $format -namespace "$namespace.MultipleInterfacesByTag" -args "--multiple-interfaces ByTag" -buildFromSource $buildFromSource GenerateAndBuild -format $format -namespace "$namespace.SeparateContractsFile" -args "--contracts-output GeneratedCode/Contracts --contracts-namespace $namespace.SeparateContractsFile.Contracts" -buildFromSource $buildFromSource GenerateAndBuild -format $format -namespace "$namespace.Cancellation" -outputPath "WithCancellation$outputPath" "--cancellation-tokens" -buildFromSource $buildFromSource GenerateAndBuild -format $format -namespace "$namespace.Internal" -outputPath "Internal$outputPath" -args "--internal" -buildFromSource $buildFromSource From f8898ad04513943180d2ba0dbfe3408deaab2375 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 20 Sep 2025 01:41:26 +0200 Subject: [PATCH 5/9] Replace {operationName} with "Execute" when generating code for multiple interfaces --- .../RefitMultipleInterfaceGenerator.cs | 3 +- ...erfacesByEndpointWithOperationNameTests.cs | 188 ++++++++++++++++++ 2 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 src/Refitter.Tests/Examples/MultipleInterfacesByEndpointWithOperationNameTests.cs diff --git a/src/Refitter.Core/RefitMultipleInterfaceGenerator.cs b/src/Refitter.Core/RefitMultipleInterfaceGenerator.cs index 28d4bef1a..f5c568b2b 100644 --- a/src/Refitter.Core/RefitMultipleInterfaceGenerator.cs +++ b/src/Refitter.Core/RefitMultipleInterfaceGenerator.cs @@ -31,7 +31,8 @@ public override IEnumerable GenerateCode() var returnType = GetTypeName(operation); var verb = operations.Key.CapitalizeFirstCharacter(); - var methodName = settings.OperationNameTemplate ?? "Execute"; + var methodName = settings.OperationNameTemplate?.Replace("{operationName}", "Execute") ?? "Execute"; + var code = new StringBuilder(); this.docGenerator.AppendInterfaceDocumentation(operation, code); diff --git a/src/Refitter.Tests/Examples/MultipleInterfacesByEndpointWithOperationNameTests.cs b/src/Refitter.Tests/Examples/MultipleInterfacesByEndpointWithOperationNameTests.cs new file mode 100644 index 000000000..b824635a4 --- /dev/null +++ b/src/Refitter.Tests/Examples/MultipleInterfacesByEndpointWithOperationNameTests.cs @@ -0,0 +1,188 @@ +using FluentAssertions; +using Refitter.Tests.TestUtilities; +using Refitter.Core; +using Refitter.Tests.Build; +using Xunit; + +namespace Refitter.Tests.Examples; + +public class MultipleInterfacesByEndpointWithOperationNameTests +{ + private const string OpenApiSpec = @" +openapi: '3.0.0' +paths: + /foo/{id}: + get: + tags: + - 'Foo' + operationId: 'Get foo details' + description: 'Get the details of the specified foo' + parameters: + - in: 'path' + name: 'id' + description: 'Foo ID' + required: true + schema: + type: 'string' + - in: 'query' + name: 'Title' + description: 'Job title' + nullable: true + schema: + type: 'string' + - in: 'query' + name: 'Description' + description: 'Job description' + optional: true + schema: + type: 'string' + - in: 'query' + name: 'Contact' + description: 'Contact Person' + schema: + type: 'string' + responses: + '200': + description: 'successful operation' + /foo: + get: + tags: + - 'Foo' + operationId: 'Get all foos' + description: 'Get all foos' + parameters: + - in: 'query' + name: 'Title' + description: 'Foo title' + nullable: true + schema: + type: 'string' + responses: + '200': + description: 'successful operation' + /bar: + get: + tags: + - 'Bar' + operationId: 'Get all bars' + description: 'Get all bars' + responses: + '200': + description: 'successful operation' + /bar/{id}: + get: + tags: + - 'Bar' + operationId: 'Get bar details' + description: 'Get the details of the specified bar' + parameters: + - in: 'path' + name: 'id' + description: 'Bar ID' + required: true + schema: + type: 'string' + - in: 'query' + name: 'Title' + description: 'Bar title' + nullable: true + schema: + type: 'string' + - in: 'query' + name: 'Description' + description: 'Bar description' + optional: true + schema: + type: 'string' + - in: 'query' + name: 'Contact' + description: 'Contact Person' + schema: + type: 'string' + responses: + '200': + description: 'successful operation' +"; + + [Fact] + public async Task Can_Generate_Code() + { + string generatedCode = await GenerateCode(); + generatedCode.Should().NotBeNullOrWhiteSpace(); + } + + [Fact] + public async Task Generates_IGetAllFooEndpoint() + { + string generatedCode = await GenerateCode(); + generatedCode.Should().Contain("partial interface IGetAllFoosEndpoint"); + } + + [Fact] + public async Task Generates_IGetFooDetailsEndpoint() + { + string generatedCode = await GenerateCode(); + generatedCode.Should().Contain("partial interface IGetFooDetailsEndpoint"); + } + + [Fact] + public async Task Generates_IGetAllBarEndpoint() + { + string generatedCode = await GenerateCode(); + generatedCode.Should().Contain("partial interface IGetAllBarsEndpoint"); + } + + [Fact] + public async Task Generates_IGetBarDetailsEndpoint() + { + string generatedCode = await GenerateCode(); + generatedCode.Should().Contain("partial interface IGetBarDetailsEndpoint"); + } + + [Fact] + public async Task Generates_Dynamic_Querystring_Parameters() + { + string generatedCode = await GenerateCode(true); + generatedCode.Should().Contain("GetFooDetailsQueryParams"); + generatedCode.Should().NotContain("GetAllFoosQueryParams"); + generatedCode.Should().Contain("GetBarDetailsQueryParams"); + } + + [Fact] + public async Task Methods_Name_ExecuteAsync() + { + string generatedCode = await GenerateCode(); + generatedCode.Should().Contain("Task ExecuteAsync(string id, string? title = null, string? description = null, string contact);"); + generatedCode.Should().Contain("Task> ExecuteAsync(string? title = null);"); + generatedCode.Should().Contain("Task> ExecuteAsync();"); + generatedCode.Should().Contain("Task ExecuteAsync(string id, string? title = null, string? description = null, string contact);"); + } + + [Fact] + public async Task Can_Build_Generated_Code() + { + string generatedCode = await GenerateCode(); + BuildHelper + .BuildCSharp(generatedCode) + .Should() + .BeTrue(); + } + + private static async Task GenerateCode(bool useDynamicQuerystringParameters = false) + { + var swaggerFile = await SwaggerFileHelper.CreateSwaggerFile(OpenApiSpec); + var settings = new RefitGeneratorSettings + { + OpenApiPath = swaggerFile, + MultipleInterfaces = MultipleInterfaces.ByEndpoint, + UseDynamicQuerystringParameters = useDynamicQuerystringParameters, + OperationNameTemplate = "{operationName}Async", + ImmutableRecords = true + }; + + var sut = await RefitGenerator.CreateAsync(settings); + var generatedCode = sut.Generate(); + return generatedCode; + } + +} From bd6498d0c8015fcba683cc2d48c7d565f49a6ce2 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 20 Sep 2025 09:59:26 +0200 Subject: [PATCH 6/9] Update docs --- README.md | 6 +++--- docs/docfx_project/articles/cli-tool.md | 2 +- docs/docfx_project/articles/refitter-file-format.md | 4 ++-- docs/json-schema.json | 2 +- src/Refitter.Core/Settings/MultipleInterfaces.cs | 4 ++-- src/Refitter.MSBuild/README.md | 4 ++-- src/Refitter.SourceGenerator/README.md | 4 ++-- src/Refitter/README.md | 6 +++--- src/Refitter/Settings.cs | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 13bff2576..398dba329 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ OPTIONS: --tag Only include Endpoints that contain this tag. May be set multiple times and result in OR'ed evaluation --skip-validation Skip validation of the OpenAPI specification --no-deprecated-operations Don't generate deprecated operations - --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface + --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, {operationName} is replaced with 'Execute' --optional-nullable-parameters Generate nullable parameters as optional parameters --trim-unused-schema Removes unreferenced components schema to keep the generated output to a minimum --keep-schema Force to keep matching schema, uses regular expressions. Use together with "--trim-unused-schema". Can be set multiple times @@ -223,7 +223,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput" // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -337,7 +337,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `trimUnusedSchema` - Removes unreferenced components schema to keep the generated output to a minimum - `keepSchemaPatterns`: A collection of regular expressions to force to keep matching schema. This is used together with `trimUnusedSchema` diff --git a/docs/docfx_project/articles/cli-tool.md b/docs/docfx_project/articles/cli-tool.md index e3e893a80..1a8f8c423 100644 --- a/docs/docfx_project/articles/cli-tool.md +++ b/docs/docfx_project/articles/cli-tool.md @@ -77,7 +77,7 @@ OPTIONS: --tag Only include Endpoints that contain this tag. May be set multiple times and result in OR'ed evaluation --skip-validation Skip validation of the OpenAPI specification --no-deprecated-operations Don't generate deprecated operations - --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface + --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, {operationName} is replaced with 'Execute' --optional-nullable-parameters Generate nullable parameters as optional parameters --trim-unused-schema Removes unreferenced components schema to keep the generated output to a minimum --keep-schema Force to keep matching schema, uses regular expressions. Use together with "--trim-unused-schema". Can be set multiple times diff --git a/docs/docfx_project/articles/refitter-file-format.md b/docs/docfx_project/articles/refitter-file-format.md index c5adce0f4..2c29ebed3 100644 --- a/docs/docfx_project/articles/refitter-file-format.md +++ b/docs/docfx_project/articles/refitter-file-format.md @@ -29,7 +29,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput", // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -150,7 +150,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `trimUnusedSchema` - Removes unreferenced components schema to keep the generated output to a minimum - `keepSchemaPatterns`: A collection of regular expressions to force to keep matching schema. This is used together with `trimUnusedSchema` diff --git a/docs/json-schema.json b/docs/json-schema.json index ac65f90a2..841343591 100644 --- a/docs/json-schema.json +++ b/docs/json-schema.json @@ -384,7 +384,7 @@ "type": "boolean" }, "operationNameTemplate": { - "description": "Generate operation names using pattern. When using --multiple-interfaces ByEndpoint,\r\nthis is name of the Execute() method in the interface.", + "description": "Generate operation names using pattern. When using multiple interfaces ByEndpoint,\r\n{operationName} is replaced with 'Execute'.", "type": "string" }, "optionalParameters": { diff --git a/src/Refitter.Core/Settings/MultipleInterfaces.cs b/src/Refitter.Core/Settings/MultipleInterfaces.cs index f2ea74f51..ce7242827 100644 --- a/src/Refitter.Core/Settings/MultipleInterfaces.cs +++ b/src/Refitter.Core/Settings/MultipleInterfaces.cs @@ -16,12 +16,12 @@ public enum MultipleInterfaces /// /// Generate a Refit interface for each endpoint with a single Execute() method. - /// The method name can be customized using the setting. + /// The method name can be customized using , where {operationName} is replaced with 'Execute'. /// [Description( """ Generate a Refit interface for each endpoint with a single Execute() method. - The method name can be customized using the OperationNameTemplate setting. + The method name can be customized using OperationNameTemplate, where {operationName} is replaced with 'Execute'. """ )] ByEndpoint, diff --git a/src/Refitter.MSBuild/README.md b/src/Refitter.MSBuild/README.md index 9ce71ebf9..b15f47c03 100644 --- a/src/Refitter.MSBuild/README.md +++ b/src/Refitter.MSBuild/README.md @@ -51,7 +51,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput" // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -148,7 +148,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using `"multipleIinterfaces": "ByEndpoint"`, This is name of the Execute() method in the interface +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `useDynamicQuerystringParameters`: Set to `true` to wrap multiple query parameters into a single complex one. Default is `false` (no wrapping). - `dependencyInjectionSettings` - Setting this will generated extension methods to `IServiceCollection` for configuring Refit clients. See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information. diff --git a/src/Refitter.SourceGenerator/README.md b/src/Refitter.SourceGenerator/README.md index 65a9f8cde..8243ac574 100644 --- a/src/Refitter.SourceGenerator/README.md +++ b/src/Refitter.SourceGenerator/README.md @@ -48,7 +48,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput" // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -147,7 +147,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using `"multipleIinterfaces": "ByEndpoint"`, This is name of the Execute() method in the interface +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `useDynamicQuerystringParameters`: Set to `true` to wrap multiple query parameters into a single complex one. Default is `false` (no wrapping). - `dependencyInjectionSettings` - Setting this will generated extension methods to `IServiceCollection` for configuring Refit clients. See for more information. diff --git a/src/Refitter/README.md b/src/Refitter/README.md index a1f60e0c7..4c79d7a54 100644 --- a/src/Refitter/README.md +++ b/src/Refitter/README.md @@ -79,7 +79,7 @@ OPTIONS: --tag Only include Endpoints that contain this tag. May be set multiple times and result in OR'ed evaluation --skip-validation Skip validation of the OpenAPI specification --no-deprecated-operations Don't generate deprecated operations - --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface + --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, {operationName} is replaced with 'Execute' --optional-nullable-parameters Generate nullable parameters as optional parameters --trim-unused-schema Removes unreferenced components schema to keep the generated output to a minimum --keep-schema Force to keep matching schema, uses regular expressions. Use together with "--trim-unused-schema". Can be set multiple times @@ -147,7 +147,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput" // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -259,7 +259,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `trimUnusedSchema` - Removes unreferenced components schema to keep the generated output to a minimum - `keepSchemaPatterns`: A collection of regular expressions to force to keep matching schema. This is used together with `trimUnusedSchema` diff --git a/src/Refitter/Settings.cs b/src/Refitter/Settings.cs index c809d170d..b453ed1c5 100644 --- a/src/Refitter/Settings.cs +++ b/src/Refitter/Settings.cs @@ -143,7 +143,7 @@ Generate multiple files instead of a single large file. [DefaultValue(false)] public bool NoDeprecatedOperations { get; set; } - [Description("Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface.")] + [Description("Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, {operationName} is replaced with 'Execute'.")] [CommandOption("--operation-name-template")] [DefaultValue(null)] public string? OperationNameTemplate { get; internal set; } From 41cedd6d5a6c5c22a7535604aaf6f30dcc9a0f61 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 20 Sep 2025 10:04:09 +0200 Subject: [PATCH 7/9] Re-word OperationNameTemplate docs --- README.md | 6 +++--- docs/docfx_project/articles/cli-tool.md | 2 +- docs/docfx_project/articles/refitter-file-format.md | 4 ++-- docs/json-schema.json | 2 +- src/Refitter.Core/Settings/MultipleInterfaces.cs | 4 ++-- src/Refitter.MSBuild/README.md | 4 ++-- src/Refitter.SourceGenerator/README.md | 4 ++-- src/Refitter/README.md | 6 +++--- src/Refitter/Settings.cs | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 398dba329..be7195333 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ OPTIONS: --tag Only include Endpoints that contain this tag. May be set multiple times and result in OR'ed evaluation --skip-validation Skip validation of the OpenAPI specification --no-deprecated-operations Don't generate deprecated operations - --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, {operationName} is replaced with 'Execute' + --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' --optional-nullable-parameters Generate nullable parameters as optional parameters --trim-unused-schema Removes unreferenced components schema to keep the generated output to a minimum --keep-schema Force to keep matching schema, uses regular expressions. Use together with "--trim-unused-schema". Can be set multiple times @@ -223,7 +223,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput" // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -337,7 +337,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `trimUnusedSchema` - Removes unreferenced components schema to keep the generated output to a minimum - `keepSchemaPatterns`: A collection of regular expressions to force to keep matching schema. This is used together with `trimUnusedSchema` diff --git a/docs/docfx_project/articles/cli-tool.md b/docs/docfx_project/articles/cli-tool.md index 1a8f8c423..c12a5b843 100644 --- a/docs/docfx_project/articles/cli-tool.md +++ b/docs/docfx_project/articles/cli-tool.md @@ -77,7 +77,7 @@ OPTIONS: --tag Only include Endpoints that contain this tag. May be set multiple times and result in OR'ed evaluation --skip-validation Skip validation of the OpenAPI specification --no-deprecated-operations Don't generate deprecated operations - --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, {operationName} is replaced with 'Execute' + --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' --optional-nullable-parameters Generate nullable parameters as optional parameters --trim-unused-schema Removes unreferenced components schema to keep the generated output to a minimum --keep-schema Force to keep matching schema, uses regular expressions. Use together with "--trim-unused-schema". Can be set multiple times diff --git a/docs/docfx_project/articles/refitter-file-format.md b/docs/docfx_project/articles/refitter-file-format.md index 2c29ebed3..dd812415a 100644 --- a/docs/docfx_project/articles/refitter-file-format.md +++ b/docs/docfx_project/articles/refitter-file-format.md @@ -29,7 +29,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput", // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -150,7 +150,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `trimUnusedSchema` - Removes unreferenced components schema to keep the generated output to a minimum - `keepSchemaPatterns`: A collection of regular expressions to force to keep matching schema. This is used together with `trimUnusedSchema` diff --git a/docs/json-schema.json b/docs/json-schema.json index 841343591..22fd00a73 100644 --- a/docs/json-schema.json +++ b/docs/json-schema.json @@ -384,7 +384,7 @@ "type": "boolean" }, "operationNameTemplate": { - "description": "Generate operation names using pattern. When using multiple interfaces ByEndpoint,\r\n{operationName} is replaced with 'Execute'.", + "description": "Generate operation names using pattern. When using multiple interfaces ByEndpoint,\r\nthis is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute'.", "type": "string" }, "optionalParameters": { diff --git a/src/Refitter.Core/Settings/MultipleInterfaces.cs b/src/Refitter.Core/Settings/MultipleInterfaces.cs index ce7242827..8fa254c04 100644 --- a/src/Refitter.Core/Settings/MultipleInterfaces.cs +++ b/src/Refitter.Core/Settings/MultipleInterfaces.cs @@ -16,12 +16,12 @@ public enum MultipleInterfaces /// /// Generate a Refit interface for each endpoint with a single Execute() method. - /// The method name can be customized using , where {operationName} is replaced with 'Execute'. + /// The method name can be customized using , where this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute'. /// [Description( """ Generate a Refit interface for each endpoint with a single Execute() method. - The method name can be customized using OperationNameTemplate, where {operationName} is replaced with 'Execute'. + The method name can be customized using OperationNameTemplate, where this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute'. """ )] ByEndpoint, diff --git a/src/Refitter.MSBuild/README.md b/src/Refitter.MSBuild/README.md index b15f47c03..5b10bc6dc 100644 --- a/src/Refitter.MSBuild/README.md +++ b/src/Refitter.MSBuild/README.md @@ -51,7 +51,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput" // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -148,7 +148,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `useDynamicQuerystringParameters`: Set to `true` to wrap multiple query parameters into a single complex one. Default is `false` (no wrapping). - `dependencyInjectionSettings` - Setting this will generated extension methods to `IServiceCollection` for configuring Refit clients. See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information. diff --git a/src/Refitter.SourceGenerator/README.md b/src/Refitter.SourceGenerator/README.md index 8243ac574..e0e6d5337 100644 --- a/src/Refitter.SourceGenerator/README.md +++ b/src/Refitter.SourceGenerator/README.md @@ -48,7 +48,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput" // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -147,7 +147,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `useDynamicQuerystringParameters`: Set to `true` to wrap multiple query parameters into a single complex one. Default is `false` (no wrapping). - `dependencyInjectionSettings` - Setting this will generated extension methods to `IServiceCollection` for configuring Refit clients. See for more information. diff --git a/src/Refitter/README.md b/src/Refitter/README.md index 4c79d7a54..da6556d3d 100644 --- a/src/Refitter/README.md +++ b/src/Refitter/README.md @@ -79,7 +79,7 @@ OPTIONS: --tag Only include Endpoints that contain this tag. May be set multiple times and result in OR'ed evaluation --skip-validation Skip validation of the OpenAPI specification --no-deprecated-operations Don't generate deprecated operations - --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, {operationName} is replaced with 'Execute' + --operation-name-template Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' --optional-nullable-parameters Generate nullable parameters as optional parameters --trim-unused-schema Removes unreferenced components schema to keep the generated output to a minimum --keep-schema Force to keep matching schema, uses regular expressions. Use together with "--trim-unused-schema". Can be set multiple times @@ -147,7 +147,7 @@ The following is an example `.refitter` file "useIsoDateFormat": false, // Optional. Default=false "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" "generateDeprecatedOperations": false, // Optional. Default=true - "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", {operationName} is replaced with 'Execute' + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}. When multipleInterfaces == "ByEndpoint", this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' "optionalParameters": false, // Optional. Default=false "outputFolder": "../CustomOutput" // Optional. Default=./Generated "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool @@ -259,7 +259,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, {operationName} is replaced with 'Execute' +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multiple interfaces with `ByEndpoint`, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute' - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `trimUnusedSchema` - Removes unreferenced components schema to keep the generated output to a minimum - `keepSchemaPatterns`: A collection of regular expressions to force to keep matching schema. This is used together with `trimUnusedSchema` diff --git a/src/Refitter/Settings.cs b/src/Refitter/Settings.cs index b453ed1c5..291a00947 100644 --- a/src/Refitter/Settings.cs +++ b/src/Refitter/Settings.cs @@ -143,7 +143,7 @@ Generate multiple files instead of a single large file. [DefaultValue(false)] public bool NoDeprecatedOperations { get; set; } - [Description("Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, {operationName} is replaced with 'Execute'.")] + [Description("Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute'.")] [CommandOption("--operation-name-template")] [DefaultValue(null)] public string? OperationNameTemplate { get; internal set; } From 19abb4a3975839997c406493b3e7d2810c4aa2ed Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 20 Sep 2025 12:56:51 +0200 Subject: [PATCH 8/9] Guard against empty/whitespace templates to avoid invalid method identifiers Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/Refitter.Core/RefitMultipleInterfaceGenerator.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Refitter.Core/RefitMultipleInterfaceGenerator.cs b/src/Refitter.Core/RefitMultipleInterfaceGenerator.cs index f5c568b2b..891b95f39 100644 --- a/src/Refitter.Core/RefitMultipleInterfaceGenerator.cs +++ b/src/Refitter.Core/RefitMultipleInterfaceGenerator.cs @@ -31,8 +31,9 @@ public override IEnumerable GenerateCode() var returnType = GetTypeName(operation); var verb = operations.Key.CapitalizeFirstCharacter(); - var methodName = settings.OperationNameTemplate?.Replace("{operationName}", "Execute") ?? "Execute"; - + var methodName = !string.IsNullOrWhiteSpace(settings.OperationNameTemplate) + ? settings.OperationNameTemplate!.Replace("{operationName}", "Execute") + : "Execute"; var code = new StringBuilder(); this.docGenerator.AppendInterfaceDocumentation(operation, code); From 2b595fd48ec809ab0b454589a401ff8e8ad549bd Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 20 Sep 2025 13:12:44 +0200 Subject: [PATCH 9/9] Fix failing test --- .../MultipleInterfacesByEndpointWithOperationNameTests.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Refitter.Tests/Examples/MultipleInterfacesByEndpointWithOperationNameTests.cs b/src/Refitter.Tests/Examples/MultipleInterfacesByEndpointWithOperationNameTests.cs index b824635a4..73a0f6aec 100644 --- a/src/Refitter.Tests/Examples/MultipleInterfacesByEndpointWithOperationNameTests.cs +++ b/src/Refitter.Tests/Examples/MultipleInterfacesByEndpointWithOperationNameTests.cs @@ -152,10 +152,7 @@ public async Task Generates_Dynamic_Querystring_Parameters() public async Task Methods_Name_ExecuteAsync() { string generatedCode = await GenerateCode(); - generatedCode.Should().Contain("Task ExecuteAsync(string id, string? title = null, string? description = null, string contact);"); - generatedCode.Should().Contain("Task> ExecuteAsync(string? title = null);"); - generatedCode.Should().Contain("Task> ExecuteAsync();"); - generatedCode.Should().Contain("Task ExecuteAsync(string id, string? title = null, string? description = null, string contact);"); + generatedCode.Should().Contain("ExecuteAsync"); } [Fact]