diff --git a/README.md b/README.md index a02dd810a..5a9d776eb 100644 --- a/README.md +++ b/README.md @@ -63,68 +63,68 @@ ARGUMENTS: [URL or input file] URL or file path to OpenAPI Specification file OPTIONS: - DEFAULT - -h, --help Prints help information - -v, --version Prints version information - -s, --settings-file Path to .refitter settings file. Specifying this will ignore all other settings (except for --output) - -n, --namespace GeneratedCode Default namespace to use for generated types - --contracts-namespace Default namespace to use for generated contracts - -o, --output Output.cs Path to Output file or folder (if multiple files are generated) - --contracts-output Output path for generated contracts. Enabling this automatically enables generating multiple files - --no-auto-generated-header Don't add header to output file - --no-accept-headers Don't add header to output file - --interface-only Don't generate contract types - --contract-only Don't generate clients - --use-api-response Return Task> instead of Task - --use-observable-response Return IObservable instead of Task - --internal Set the accessibility of the generated types to 'internal' - --cancellation-tokens Use cancellation tokens - --no-operation-headers Don't generate operation headers - --no-logging Don't log errors or collect telemetry - --additional-namespace Add additional namespace to generated types - --exclude-namespace Exclude namespace on generated types - --use-iso-date-format Explicitly format date query string parameters in ISO 8601 standard date format using delimiters (2023-06-15) - --multiple-interfaces Generate a Refit interface for each endpoint. May be one of ByEndpoint, ByTag - --multiple-files Generate multiple files instead of a single large file. - The output files can be the following: - - RefitInterfaces.cs - - DependencyInjection.cs - - Contracts.cs - --match-path Only include Paths that match the provided regular expression. May be set multiple times - --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 + DEFAULT + -h, --help Prints help information + -v, --version Prints version information + -s, --settings-file Path to .refitter settings file. Specifying this will ignore all other settings (except for --output) + -n, --namespace GeneratedCode Default namespace to use for generated types + --contracts-namespace Default namespace to use for generated contracts + -o, --output Output.cs Path to Output file or folder (if multiple files are generated) + --contracts-output Output path for generated contracts. Enabling this automatically enables generating multiple files + --no-auto-generated-header Don't add header to output file + --no-accept-headers Don't add header to output file + --interface-only Don't generate contract types + --contract-only Don't generate clients + --use-api-response Return Task> instead of Task + --use-observable-response Return IObservable instead of Task + --internal Set the accessibility of the generated types to 'internal' + --cancellation-tokens Use cancellation tokens + --no-operation-headers Don't generate operation headers + --no-logging Don't log errors or collect telemetry + --additional-namespace Add additional namespace to generated types + --exclude-namespace Exclude namespace on generated types + --use-iso-date-format Explicitly format date query string parameters in ISO 8601 standard date format using delimiters (2023-06-15) + --multiple-interfaces Generate a Refit interface for each endpoint. May be one of ByEndpoint, ByTag + --multiple-files Generate multiple files instead of a single large file. + The output files can be the following: + - RefitInterfaces.cs + - DependencyInjection.cs + - Contracts.cs + --match-path Only include Paths that match the provided regular expression. May be set multiple times + --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 - --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 - --no-banner Don't show donation banner - --skip-default-additional-properties Set to true to skip default additional properties - --operation-name-generator Default The NSwag IOperationNameGenerator implementation to use. - May be one of: - - Default - - MultipleClientsFromOperationId - - MultipleClientsFromPathSegments - - MultipleClientsFromFirstTagAndOperationId - - MultipleClientsFromFirstTagAndOperationName - - MultipleClientsFromFirstTagAndPathSegments - - SingleClientFromOperationId - - SingleClientFromPathSegments - See https://refitter.github.io/api/Refitter.Core.OperationNameGeneratorTypes.html for more information - --immutable-records Generate contracts as immutable records instead of classes - --use-apizr Use Apizr by: - - Adding a final IApizrRequestOptions options parameter to all generated methods - - Providing cancellation tokens by Apizr request options instead of a dedicated parameter - - Using method overloads instead of optional parameters - See https://refitter.github.io for more information and https://www.apizr.net to get started with Apizr - --use-dynamic-querystring-parameters Enable wrapping multiple query parameters into a single complex one. Default is no wrapping. - See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information - --use-polymorphic-serialization Use System.Text.Json polymorphic serialization. - Replaces NSwag JsonInheritanceConverter attributes with System.Text.Json JsonPolymorphicAttributes. - To have the native support of inheritance (de)serialization and fallback to base types when - payloads with (yet) unknown types are offered by newer versions of an API - See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information - --disposable Generate refit clients that implement IDisposable + --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 + --no-banner Don't show donation banner + --skip-default-additional-properties Set to true to skip default additional properties + --operation-name-generator Default The NSwag IOperationNameGenerator implementation to use. + May be one of: + - Default + - MultipleClientsFromOperationId + - MultipleClientsFromPathSegments + - MultipleClientsFromFirstTagAndOperationId + - MultipleClientsFromFirstTagAndOperationName + - MultipleClientsFromFirstTagAndPathSegments + - SingleClientFromOperationId + - SingleClientFromPathSegments + See https://refitter.github.io/api/Refitter.Core.OperationNameGeneratorTypes.html for more information + --immutable-records Generate contracts as immutable records instead of classes + --use-apizr Use Apizr by: + - Adding a final IApizrRequestOptions options parameter to all generated methods + - Providing cancellation tokens by Apizr request options instead of a dedicated parameter + - Using method overloads instead of optional parameters + See https://refitter.github.io for more information and https://www.apizr.net to get started with Apizr + --use-dynamic-querystring-parameters Enable wrapping multiple query parameters into a single complex one. Default is no wrapping. + See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information + --use-polymorphic-serialization Use System.Text.Json polymorphic serialization. + Replaces NSwag JsonInheritanceConverter attributes with System.Text.Json JsonPolymorphicAttributes. + To have the native support of inheritance (de)serialization and fallback to base types when + payloads with (yet) unknown types are offered by newer versions of an API + See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information + --disposable Generate refit clients that implement IDisposable ``` To generate code from an OpenAPI specifications file, run the following: @@ -139,7 +139,7 @@ This will generate a file called `Output.cs` which contains the Refit interface Refitter is available as a C# Source Generator that uses the [Refitter.Core](https://github.com/christianhelle/refitter/tree/main/src/Refitter.Core) library for generating a REST API Client using the [Refit](https://github.com/reactiveui/refit) library. Refitter can generate the Refit interface from OpenAPI specifications. Refitter could format the generated Refit interface to be managed by [Apizr](https://www.apizr.net) and generate some registration helpers too. -The Refitter source generator is a bit untraditional in a sense that it creates a folder called `Generated` in the same location as the `.refitter` file and generates files to disk under the `Generated` folder (can be changed with `--outputFolder`). The source generator output should be included in the project and committed to source control. This is done because there is no other way to trigger the Refit source generator to pickup the Refitter generated code +The Refitter source generator is a bit untraditional in a sense that it creates a folder called `Generated` in the same location as the `.refitter` file and generates files to disk under the `Generated` folder (can be changed with `--outputFolder`). The source generator output should be included in the project and committed to source control. This is done because there is no other way to trigger the Refit source generator to pickup the Refitter generated code ***(Translation: I couldn't for the life of me figure how to get that to work, sorry)*** @@ -220,8 +220,8 @@ The following is an example `.refitter` file "dependencyInjectionSettings": { // Optional "baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually "httpMessageHandlers": [ // Optional - "AuthorizationMessageHandler", - "TelemetryMessageHandler" + "AuthorizationMessageHandler", + "TelemetryMessageHandler" ], "usePolly": true, // DEPRECATED - Use "transientErrorHandler": "None|Polly|HttpResilience" instead "transientErrorHandler": "HttpResilience", // Optional. Set this to configure transient error handling with a retry policy that uses a jittered backoff. May be one of None, Polly, HttpResilience @@ -267,6 +267,7 @@ The following is an example `.refitter` file "generateNativeRecords": false, "generateDefaultValues": true, "inlineNamedAny": false, + "dateFormat": "yyyy-MM-dd", "excludedTypeNames": [ "ExcludedTypeFoo", "ExcludedTypeBar" @@ -350,6 +351,7 @@ The following is an example `.refitter` file - `generateNativeRecords` - Default is false - `generateDefaultValues` - Default is true - `inlineNamedAny` - Default is false + - `dateFormat` - Default is `yyyy-MM-dd` - `excludedTypeNames` - Default is empty ## MSBuild @@ -398,7 +400,7 @@ In the example above, the `nuget.config` file is placed under the `refitter` fol ### Refitter.MSBuild package -Refitter ships with an MSBuild custom task that is distributed as a NuGet package and includes the Refitter CLI binary. This will simplify generating code from OpenAPI specifications at build time. +Refitter ships with an MSBuild custom task that is distributed as a NuGet package and includes the Refitter CLI binary. This will simplify generating code from OpenAPI specifications at build time. To use the package, install `Refitter.MSBuild` @@ -2073,38 +2075,38 @@ public partial interface ISwaggerPetstoreOpenAPI30 Task DeleteUser(string username); -} +} public class UpdatePetWithFormQueryParams { - + /// /// Name of pet that needs to be updated /// - [Query] + [Query] public string Name { get; set; } /// /// Status of pet that needs to be updated /// - [Query] + [Query] public string Status { get; set; } } public class LoginUserQueryParams { - + /// /// The user name for login /// - [Query] + [Query] public string Username { get; set; } /// /// The password for login in clear text /// - [Query] + [Query] public string Password { get; set; } } @@ -2146,7 +2148,7 @@ internal class Program } ``` -The `RestService` class generates an implementation of `ISwaggerPetstore` that uses `HttpClient` to make its calls. +The `RestService` class generates an implementation of `ISwaggerPetstore` that uses `HttpClient` to make its calls. The code above when run will output something like this: @@ -2246,8 +2248,8 @@ which will generate an extension method to `IServiceCollection` called `Configur ```cs public static IServiceCollection ConfigureRefitClients( - this IServiceCollection services, - Action? builder = default, + this IServiceCollection services, + Action? builder = default, RefitSettings? settings = default) { var clientBuilderISwaggerPetstore = services @@ -2291,8 +2293,8 @@ Will generate a single `ConfigureRefitClients()` extension methods that may cont ```csharp public static IServiceCollection ConfigureRefitClients( - this IServiceCollection services, - Action? builder = default, + this IServiceCollection services, + Action? builder = default, RefitSettings? settings = default) { var clientBuilderIPetApi = services @@ -2431,7 +2433,7 @@ public static IServiceCollection ConfigurePetstoreApiApizrManager( .WithPriority() .WithOptionalMediation() .WithFileTransferOptionalMediation(); - + return services.AddApizrManagerFor(optionsBuilder); } ``` @@ -2444,7 +2446,7 @@ This comes in handy especially when generating multiple interfaces, by tag or en "namespace": "Petstore", "useDynamicQuerystringParameters": true, "multipleInterfaces": "ByTag", - "naming": { + "naming": { "useOpenApiTitle": false, "interfaceName": "Petstore" }, @@ -2494,7 +2496,7 @@ public static IServiceCollection ConfigurePetstoreApizrManagers( .WithPriority() .WithOptionalMediation() .WithFileTransferOptionalMediation(); - + return services.AddApizr( registry => registry .AddManagerFor() @@ -2538,8 +2540,8 @@ public static IApizrManager BuildPetstore30ApizrManag .WithAkavacheCacheHandler() .WithAutoMapperMappingHandler(new MapperConfiguration(config => { /* YOUR_MAPPINGS_HERE */ })) .WithPriority(); - - return ApizrBuilder.Current.CreateManagerFor(optionsBuilder); + + return ApizrBuilder.Current.CreateManagerFor(optionsBuilder); } ``` @@ -2551,7 +2553,7 @@ This comes in handy especially when generating multiple interfaces, by tag or en "namespace": "Petstore", "useDynamicQuerystringParameters": true, "multipleInterfaces": "ByTag", - "naming": { + "naming": { "useOpenApiTitle": false, "interfaceName": "Petstore" }, @@ -2585,7 +2587,7 @@ public static IApizrRegistry BuildPetstoreApizrManagers(Action { /* YOUR_MAPPINGS_HERE */ })) .WithPriority(); - + return ApizrBuilder.Current.CreateRegistry( registry => registry .AddManagerFor() @@ -2609,7 +2611,7 @@ To know how to make Apizr fit your needs, please refer to the [Apizr documentati Once you called the generated method, you will get an `IApizrManager` instance that you can use to make requests to the API. Here's an example of how to use it: ```csharp -var result = await petstoreManager.ExecuteAsync((api, opt) => api.GetPetById(1, opt), +var result = await petstoreManager.ExecuteAsync((api, opt) => api.GetPetById(1, opt), options => options // Whatever final request options you want to apply .WithPriority(Priority.Background) .WithHeaders(["HeaderKey1: HeaderValue1"]) diff --git a/src/Refitter.Core/ParameterExtractor.cs b/src/Refitter.Core/ParameterExtractor.cs index f6f82751b..efde39815 100644 --- a/src/Refitter.Core/ParameterExtractor.cs +++ b/src/Refitter.Core/ParameterExtractor.cs @@ -11,7 +11,7 @@ public static IEnumerable GetParameters( CSharpOperationModel operationModel, OpenApiOperation operation, RefitGeneratorSettings settings, - string dynamicQuerystringParameterType, + string dynamicQuerystringParameterType, out string? dynamicQuerystringParameters) { var routeParameters = operationModel.Parameters @@ -46,7 +46,7 @@ public static IEnumerable GetParameters( var generatedAliasAsAttribute = string.IsNullOrWhiteSpace(GetAliasAsAttribute(p)) ? string.Empty : $"[{GetAliasAsAttribute(p)}]"; - + return $"{generatedAliasAsAttribute}StreamPart {p.VariableName}"; }) .ToList(); @@ -90,7 +90,8 @@ private static string GetQueryAttribute(CSharpParameterModel parameter, RefitGen return (parameter, settings) switch { { parameter.IsArray: true } => "Query(CollectionFormat.Multi)", - { parameter.IsDate: true, settings.UseIsoDateFormat: true } => "Query(Format = \"yyyy-MM-dd\")", + { parameter.IsDateOrDateTime: true, settings.UseIsoDateFormat: true } => "Query(Format = \"yyyy-MM-dd\")", + { parameter.IsDateOrDateTime: true, settings.CodeGeneratorSettings: not null } => $"Query(Format = \"{settings.CodeGeneratorSettings?.DateFormat}\")", _ => "Query", }; } @@ -211,7 +212,7 @@ private static List GetQueryParameters(CSharpOperationModel operationMod } dynamicQuerystringParametersCodeBuilder.AppendLine( - $$""" + $$""" {{modifier}} {{classStyle}} {{dynamicQuerystringParameterType}} { """); @@ -224,7 +225,7 @@ private static List GetQueryParameters(CSharpOperationModel operationMod { {{initializedParametersCodeBuilder}} } - """); + """); } dynamicQuerystringParametersCodeBuilder.AppendLine( diff --git a/src/Refitter.Core/Settings/CodeGeneratorSettings.cs b/src/Refitter.Core/Settings/CodeGeneratorSettings.cs index ed97dc2ba..b56556bde 100644 --- a/src/Refitter.Core/Settings/CodeGeneratorSettings.cs +++ b/src/Refitter.Core/Settings/CodeGeneratorSettings.cs @@ -159,6 +159,8 @@ public class CodeGeneratorSettings /// public string[] ExcludedTypeNames { get; set; } = Array.Empty(); + public string DateFormat { get; set; } = "yyyy-MM-dd"; + /// /// Gets or sets a custom . /// diff --git a/src/Refitter.SourceGenerator/README.md b/src/Refitter.SourceGenerator/README.md index 1c21858f4..0dc859a29 100644 --- a/src/Refitter.SourceGenerator/README.md +++ b/src/Refitter.SourceGenerator/README.md @@ -2,7 +2,7 @@ Refitter is available as a C# Source Generator that uses the [Refitter.Core](https://github.com/christianhelle/refitter/tree/main/src/Refitter.Core) library for generating a REST API Client using the [Refit](https://github.com/reactiveui/refit) library. Refitter can generate the Refit interface from OpenAPI specifications. Refitter could format the generated Refit interface to be managed by [Apizr](https://www.apizr.net) (v6+) and generate some registration helpers too. -The Refitter source generator is a bit untraditional in a sense that it creates a folder called `Generated` in the same location as the `.refitter` file and generates files to disk under the `Generated` folder (can be changed with `--outputFolder`). The source generator output should be included in the project and committed to source control. This is done because there is no other way to trigger the Refit source generator to pickup the Refitter generated code +The Refitter source generator is a bit untraditional in a sense that it creates a folder called `Generated` in the same location as the `.refitter` file and generates files to disk under the `Generated` folder (can be changed with `--outputFolder`). The source generator output should be included in the project and committed to source control. This is done because there is no other way to trigger the Refit source generator to pickup the Refitter generated code ***(Translation: I couldn't for the life of me figure how to get that to work, sorry)*** @@ -71,9 +71,9 @@ The following is an example `.refitter` file "dependencyInjectionSettings": { // Optional "baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually "httpMessageHandlers": [ // Optional - "AuthorizationMessageHandler", - "TelemetryMessageHandler" - ], + "AuthorizationMessageHandler", + "TelemetryMessageHandler" + ], "transientErrorHandler": "Polly", // Optional. Value=None|Polly|HttpResilience "maxRetryCount": 3, // Optional. Default=6 "firstBackoffRetryInSeconds": 0.5 // Optional. Default=1.0 @@ -116,6 +116,7 @@ The following is an example `.refitter` file "generateNativeRecords": false, "generateDefaultValues": true, "inlineNamedAny": false, + "dateFormat": "yyyy-MM-dd", "excludedTypeNames": [ "ExcludedTypeFoo", "ExcludedTypeBar" @@ -151,7 +152,7 @@ The following is an example `.refitter` file - `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. - `baseUrl` - Used as the HttpClient base address. Leave this blank to manually set the base URL - `httpMessageHandlers` - A collection of `HttpMessageHandler` that is added to the HttpClient pipeline - - `transientErrorHandler` - This is the transient error handler to use. Possible values are `None`, `Polly`, and `HttpResilience`. Default is `None` + - `transientErrorHandler` - This is the transient error handler to use. Possible values are `None`, `Polly`, and `HttpResilience`. Default is `None` - `maxRetryCount` - This is the max retry count used in the Polly retry policy. Default is 6 - `firstBackoffRetryInSeconds` - This is the duration of the initial retry backoff. Default is 1 second - `apizrSettings` - Setting this will format Refit interface to be managed by Apizr. See https://www.apizr.net for more information @@ -191,4 +192,5 @@ The following is an example `.refitter` file - `generateNativeRecords` - Default is false - `generateDefaultValues` - Default is true - `inlineNamedAny` - Default is false + - `dateFormat` - Default is `yyyy-MM-dd` - `excludedTypeNames` - Default is empty diff --git a/src/Refitter.Tests/Examples/CustomDateFormatTests.cs b/src/Refitter.Tests/Examples/CustomDateFormatTests.cs new file mode 100644 index 000000000..0f23a145b --- /dev/null +++ b/src/Refitter.Tests/Examples/CustomDateFormatTests.cs @@ -0,0 +1,132 @@ +using FluentAssertions; +using Refitter.Core; +using Refitter.Tests.Build; +using Xunit; + +namespace Refitter.Tests.Examples; + +public class CustomDateFormatTests +{ + + private const string OpenApiSpec = @" +{ + ""swagger"": ""2.0"", + ""info"": { + ""title"": ""XX"", + ""version"": ""0.0.0"" + }, + ""host"": ""x.io"", + ""basePath"": ""/"", + ""schemes"": [ + ""https"" + ], + ""paths"": { + ""/t/dummy/{employee_id}"": { + ""get"": { + ""summary"": ""X"", + ""description"": ""X"", + ""operationId"": ""dummy"", + ""parameters"": [ + { + ""name"": ""employee_id"", + ""in"": ""path"", + ""description"": ""the specific employee"", + ""required"": true, + ""format"": ""int64"", + ""type"": ""integer"" + }, + { + ""name"": ""valid_from"", + ""in"": ""query"", + ""description"": ""the start of the period"", + ""required"": true, + ""format"": ""date"", + ""type"": ""string"" + }, + { + ""name"": ""valid_to"", + ""in"": ""query"", + ""description"": ""the end of the period"", + ""required"": true, + ""format"": ""date"", + ""type"": ""string"" + }, + { + ""name"": ""test_time"", + ""in"": ""query"", + ""description"": ""test parameter"", + ""required"": true, + ""format"": ""time"", + ""type"": ""string"" + } + ], + ""responses"": { + ""200"": { + ""description"": ""No response was specified"" + } + } + } + }, + } +} +"; + + + [Fact] + public async Task Can_Generate_Code() + { + string generateCode = await GenerateCode(); + generateCode.Should().NotBeNullOrWhiteSpace(); + } + + [Fact] + public async Task GeneratedCode_Contains_Date_Format_String() + { + string generateCode = await GenerateCode(); + generateCode.Should().Contain(@"[Query(Format = ""yyyy-MM-ddThh:mm:ssZ"")] "); + } + + [Fact] + public async Task GeneratedCode_Contains_TimeSpan_Parameter() + { + string generateCode = await GenerateCode(); + generateCode.Should().Contain("[Query] System.TimeSpan"); + } + + [Fact] + public async Task Can_Build_Generated_Code() + { + string generateCode = await GenerateCode(); + BuildHelper + .BuildCSharp(generateCode) + .Should() + .BeTrue(); + } + + private static async Task GenerateCode() + { + var swaggerFile = await CreateSwaggerFile(OpenApiSpec); + var settings = new RefitGeneratorSettings + { + OpenApiPath = swaggerFile, + CodeGeneratorSettings = new CodeGeneratorSettings + { + DateFormat = "yyyy-MM-ddThh:mm:ssZ" + } + }; + + var sut = await RefitGenerator.CreateAsync(settings); + var generateCode = sut.Generate(); + return generateCode; + } + + private static async Task CreateSwaggerFile(string contents) + { + var filename = $"{Guid.NewGuid()}.json"; + var folder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(folder); + var swaggerFile = Path.Combine(folder, filename); + await File.WriteAllTextAsync(swaggerFile, contents); + return swaggerFile; + } +} diff --git a/src/Refitter/README.md b/src/Refitter/README.md index cde830125..7e9fcbb51 100644 --- a/src/Refitter/README.md +++ b/src/Refitter/README.md @@ -47,68 +47,68 @@ ARGUMENTS: [URL or input file] URL or file path to OpenAPI Specification file OPTIONS: - DEFAULT - -h, --help Prints help information - -v, --version Prints version information - -s, --settings-file Path to .refitter settings file. Specifying this will ignore all other settings (except for --output) - -n, --namespace GeneratedCode Default namespace to use for generated types - --contracts-namespace Default namespace to use for generated contracts - -o, --output Output.cs Path to Output file or folder (if multiple files are generated) - --contracts-output Output path for generated contracts. Enabling this automatically enables generating multiple files - --no-auto-generated-header Don't add header to output file - --no-accept-headers Don't add header to output file - --interface-only Don't generate contract types - --contract-only Don't generate clients - --use-api-response Return Task> instead of Task - --use-observable-response Return IObservable instead of Task - --internal Set the accessibility of the generated types to 'internal' - --cancellation-tokens Use cancellation tokens - --no-operation-headers Don't generate operation headers - --no-logging Don't log errors or collect telemetry - --additional-namespace Add additional namespace to generated types - --exclude-namespace Exclude namespace on generated types - --use-iso-date-format Explicitly format date query string parameters in ISO 8601 standard date format using delimiters (2023-06-15) - --multiple-interfaces Generate a Refit interface for each endpoint. May be one of ByEndpoint, ByTag - --multiple-files Generate multiple files instead of a single large file. - The output files can be the following: - - RefitInterfaces.cs - - DependencyInjection.cs - - Contracts.cs - --match-path Only include Paths that match the provided regular expression. May be set multiple times - --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 + DEFAULT + -h, --help Prints help information + -v, --version Prints version information + -s, --settings-file Path to .refitter settings file. Specifying this will ignore all other settings (except for --output) + -n, --namespace GeneratedCode Default namespace to use for generated types + --contracts-namespace Default namespace to use for generated contracts + -o, --output Output.cs Path to Output file or folder (if multiple files are generated) + --contracts-output Output path for generated contracts. Enabling this automatically enables generating multiple files + --no-auto-generated-header Don't add header to output file + --no-accept-headers Don't add header to output file + --interface-only Don't generate contract types + --contract-only Don't generate clients + --use-api-response Return Task> instead of Task + --use-observable-response Return IObservable instead of Task + --internal Set the accessibility of the generated types to 'internal' + --cancellation-tokens Use cancellation tokens + --no-operation-headers Don't generate operation headers + --no-logging Don't log errors or collect telemetry + --additional-namespace Add additional namespace to generated types + --exclude-namespace Exclude namespace on generated types + --use-iso-date-format Explicitly format date query string parameters in ISO 8601 standard date format using delimiters (2023-06-15) + --multiple-interfaces Generate a Refit interface for each endpoint. May be one of ByEndpoint, ByTag + --multiple-files Generate multiple files instead of a single large file. + The output files can be the following: + - RefitInterfaces.cs + - DependencyInjection.cs + - Contracts.cs + --match-path Only include Paths that match the provided regular expression. May be set multiple times + --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 - --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 - --no-banner Don't show donation banner - --skip-default-additional-properties Set to true to skip default additional properties - --operation-name-generator Default The NSwag IOperationNameGenerator implementation to use. - May be one of: - - Default - - MultipleClientsFromOperationId - - MultipleClientsFromPathSegments - - MultipleClientsFromFirstTagAndOperationId - - MultipleClientsFromFirstTagAndOperationName - - MultipleClientsFromFirstTagAndPathSegments - - SingleClientFromOperationId - - SingleClientFromPathSegments - See https://refitter.github.io/api/Refitter.Core.OperationNameGeneratorTypes.html for more information - --immutable-records Generate contracts as immutable records instead of classes - --use-apizr Use Apizr by: - - Adding a final IApizrRequestOptions options parameter to all generated methods - - Providing cancellation tokens by Apizr request options instead of a dedicated parameter - - Using method overloads instead of optional parameters - See https://refitter.github.io for more information and https://www.apizr.net to get started with Apizr - --use-dynamic-querystring-parameters Enable wrapping multiple query parameters into a single complex one. Default is no wrapping. - See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information - --use-polymorphic-serialization Use System.Text.Json polymorphic serialization. - Replaces NSwag JsonInheritanceConverter attributes with System.Text.Json JsonPolymorphicAttributes. - To have the native support of inheritance (de)serialization and fallback to base types when - payloads with (yet) unknown types are offered by newer versions of an API - See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information - --disposable Generate refit clients that implement IDisposable + --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 + --no-banner Don't show donation banner + --skip-default-additional-properties Set to true to skip default additional properties + --operation-name-generator Default The NSwag IOperationNameGenerator implementation to use. + May be one of: + - Default + - MultipleClientsFromOperationId + - MultipleClientsFromPathSegments + - MultipleClientsFromFirstTagAndOperationId + - MultipleClientsFromFirstTagAndOperationName + - MultipleClientsFromFirstTagAndPathSegments + - SingleClientFromOperationId + - SingleClientFromPathSegments + See https://refitter.github.io/api/Refitter.Core.OperationNameGeneratorTypes.html for more information + --immutable-records Generate contracts as immutable records instead of classes + --use-apizr Use Apizr by: + - Adding a final IApizrRequestOptions options parameter to all generated methods + - Providing cancellation tokens by Apizr request options instead of a dedicated parameter + - Using method overloads instead of optional parameters + See https://refitter.github.io for more information and https://www.apizr.net to get started with Apizr + --use-dynamic-querystring-parameters Enable wrapping multiple query parameters into a single complex one. Default is no wrapping. + See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information + --use-polymorphic-serialization Use System.Text.Json polymorphic serialization. + Replaces NSwag JsonInheritanceConverter attributes with System.Text.Json JsonPolymorphicAttributes. + To have the native support of inheritance (de)serialization and fallback to base types when + payloads with (yet) unknown types are offered by newer versions of an API + See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information + --disposable Generate refit clients that implement IDisposable ``` ### .Refitter File format @@ -174,8 +174,8 @@ The following is an example `.refitter` file "dependencyInjectionSettings": { // Optional "baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually "httpMessageHandlers": [ // Optional - "AuthorizationMessageHandler", - "TelemetryMessageHandler" + "AuthorizationMessageHandler", + "TelemetryMessageHandler" ], "transientErrorHandler": "Polly", // Optional. Value=None|Polly|HttpResilience "maxRetryCount": 3, // Optional. Default=6 @@ -219,6 +219,7 @@ The following is an example `.refitter` file "generateNativeRecords": false, "generateDefaultValues": true, "inlineNamedAny": false, + "dateFormat": "yyyy-MM-dd", "excludedTypeNames": [ "ExcludedTypeFoo", "ExcludedTypeBar" @@ -301,6 +302,7 @@ The following is an example `.refitter` file - `generateNativeRecords` - Default is false - `generateDefaultValues` - Default is true - `inlineNamedAny` - Default is false + - `dateFormat` - Default is `yyyy-MM-dd` - `excludedTypeNames` - Default is empty To generate code from an OpenAPI specifications file, run the following: @@ -1519,38 +1521,38 @@ public partial interface ISwaggerPetstoreOpenAPI30 Task DeleteUser(string username); -} +} public class UpdatePetWithFormQueryParams { - + /// /// Name of pet that needs to be updated /// - [Query] + [Query] public string Name { get; set; } /// /// Status of pet that needs to be updated /// - [Query] + [Query] public string Status { get; set; } } public class LoginUserQueryParams { - + /// /// The user name for login /// - [Query] + [Query] public string Username { get; set; } /// /// The password for login in clear text /// - [Query] + [Query] public string Password { get; set; } } @@ -1592,7 +1594,7 @@ internal class Program } ``` -The `RestService` class generates an implementation of `ISwaggerPetstore` that uses `HttpClient` to make its calls. +The `RestService` class generates an implementation of `ISwaggerPetstore` that uses `HttpClient` to make its calls. The code above when run will output something like this: @@ -1691,8 +1693,8 @@ which will generate an extension method to `IServiceCollection` called `Configur ```cs public static IServiceCollection ConfigureRefitClients( - this IServiceCollection services, - Action? builder = default, + this IServiceCollection services, + Action? builder = default, RefitSettings? settings = default) { var clientBuilderISwaggerPetstore = services @@ -1736,8 +1738,8 @@ Will generate a single `ConfigureRefitClients()` extension methods that may cont ```csharp public static IServiceCollection ConfigureRefitClients( - this IServiceCollection services, - Action? builder = default, + this IServiceCollection services, + Action? builder = default, RefitSettings? settings = default) { var clientBuilderIPetApi = services @@ -1874,7 +1876,7 @@ public static IServiceCollection ConfigurePetstoreApiApizrManager( .WithAutoMapperMappingHandler() .WithPriority() .WithFileTransferMediation(); - + return services.AddApizrManagerFor(optionsBuilder); } ``` @@ -1887,7 +1889,7 @@ This comes in handy especially when generating multiple interfaces, by tag or en "namespace": "Petstore", "useDynamicQuerystringParameters": true, "multipleInterfaces": "ByTag", - "naming": { + "naming": { "useOpenApiTitle": false, "interfaceName": "Petstore" }, @@ -1935,7 +1937,7 @@ public static IServiceCollection ConfigurePetstoreApizrManagers( .WithAutoMapperMappingHandler() .WithPriority() .WithFileTransferMediation(); - + return services.AddApizr( registry => registry .AddManagerFor() @@ -1980,8 +1982,8 @@ public static IApizrManager BuildPetstore30ApizrManag .WithAutoMapperMappingHandler(new MapperConfiguration(config => { /* YOUR_MAPPINGS_HERE */ })) .WithPriority() .WithFileTransfer(); - - return ApizrBuilder.Current.CreateManagerFor(optionsBuilder); + + return ApizrBuilder.Current.CreateManagerFor(optionsBuilder); } ``` @@ -1993,7 +1995,7 @@ This comes in handy especially when generating multiple interfaces, by tag or en "namespace": "Petstore", "useDynamicQuerystringParameters": true, "multipleInterfaces": "ByTag", - "naming": { + "naming": { "useOpenApiTitle": false, "interfaceName": "Petstore" }, @@ -2027,7 +2029,7 @@ public static IApizrRegistry BuildPetstoreApizrManagers(Action { /* YOUR_MAPPINGS_HERE */ })) .WithPriority() .WithFileTransferMediation(); - + return ApizrBuilder.Current.CreateRegistry( registry => registry .AddManagerFor() @@ -2051,7 +2053,7 @@ To know how to make Apizr fit your needs, please refer to the [Apizr documentati Once you called the generated method, you will get an `IApizrManager` instance that you can use to make requests to the API. Here's an example of how to use it: ```csharp -var result = await petstoreManager.ExecuteAsync((api, opt) => api.GetPetById(1, opt), +var result = await petstoreManager.ExecuteAsync((api, opt) => api.GetPetById(1, opt), options => options // Whatever final request options you want to apply .WithPriority(Priority.Background) .WithHeaders(["HeaderKey1: HeaderValue1"])