Skip to content

Commit

Permalink
Merge pull request #543 from christianhelle/disposable
Browse files Browse the repository at this point in the history
Generate IDisposable Refit Interfaces
  • Loading branch information
christianhelle authored Nov 26, 2024
2 parents 7693c70 + 515f15e commit 555d08c
Show file tree
Hide file tree
Showing 13 changed files with 164 additions and 78 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,12 @@ OPTIONS:
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
--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:
Expand Down Expand Up @@ -210,7 +215,8 @@ The following is an example `.refitter` file
"operationNameGenerator": "Default", // Optional. May be one of Default, MultipleClientsFromOperationId, MultipleClientsFromPathSegments, MultipleClientsFromFirstTagAndOperationId, MultipleClientsFromFirstTagAndOperationName, MultipleClientsFromFirstTagAndPathSegments, SingleClientFromOperationId, SingleClientFromPathSegments
"immutableRecords": false,
"useDynamicQuerystringParameters": true, // Optional. Default=false
"usePolymorphicSerialization", false, // Optional. Default=false
"usePolymorphicSerialization": true, // Optional. Default=false
"generateDisposableClients": true, // Optional. Default=false
"dependencyInjectionSettings": { // Optional
"baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually
"httpMessageHandlers": [ // Optional
Expand Down
15 changes: 9 additions & 6 deletions docs/docfx_project/articles/cli-tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,19 @@ OPTIONS:
- 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 Set to true to use Apizr by:
--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 Set to <c>true</c> to wrap multiple query parameters into a single complex one. Default is <c>false</c> (no wrapping).
See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information
--use-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
--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:
Expand Down
3 changes: 2 additions & 1 deletion docs/docfx_project/articles/refitter-file-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ The following is an example `.refitter` file
"operationNameGenerator": "Default", // Optional. May be one of Default, MultipleClientsFromOperationId, MultipleClientsFromPathSegments, MultipleClientsFromFirstTagAndOperationId, MultipleClientsFromFirstTagAndOperationName, MultipleClientsFromFirstTagAndPathSegments, SingleClientFromOperationId, SingleClientFromPathSegments
"immutableRecords": false,
"useDynamicQuerystringParameters": false, // Optional. Default=false
"usePolymorphicSerialization": false, // Optional. Default=false
"usePolymorphicSerialization": true, // Optional. Default=false
"generateDisposableClients": true, // Optional. Default=false
"dependencyInjectionSettings": { // Optional
"baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually
"httpMessageHandlers": [ // Optional
Expand Down
8 changes: 8 additions & 0 deletions docs/json-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@
"type": "boolean",
"description": "Set to `true` to generate multiple files. Refit interface(s) are written to a file called `RefitInterfaces.cs`, Contracts are written to a file called `Contracts.cs`, and Dependency Injection is written to a file called `DependencyInjection.cs`"
},
"usePolymorphicSerialization": {
"type": "boolean",
"description": "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"
},
"generateDisposableClients": {
"type": "boolean",
"description": "Set to `true` to generate disposable clients. Refit interfaces are generated as disposable clients."
},
"dependencyInjectionSettings": {
"type": "object",
"properties": {
Expand Down
6 changes: 3 additions & 3 deletions src/Refitter.Core/RefitInterfaceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,13 @@ private string GenerateInterfaceDeclaration(out string interfaceName)
interfaceName = $"I{title.CapitalizeFirstCharacter()}";

var inheritance = settings.GenerateDisposableClients
? ": IDisposable"
? " : IDisposable"
: null;

var modifier = settings.TypeAccessibility.ToString().ToLowerInvariant();
return $"""
{Separator}{GetGeneratedCodeAttribute()}
{Separator}{modifier} partial interface {interfaceName} {inheritance}
{Separator}{modifier} partial interface {interfaceName}{inheritance}
""";
}

Expand Down
9 changes: 2 additions & 7 deletions src/Refitter.Core/RefitInterfaceImports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ public static string[] GetImportedNamespaces(RefitGeneratorSettings settings)
{
var namespaces = new List<string>(defaultNamespases);

if(settings.GenerateDisposableClients)
{
namespaces.Add("System");
}

if (settings.ApizrSettings?.WithRequestOptions == true)
{
namespaces.Add("Apizr.Configuring.Request");
Expand All @@ -44,7 +39,7 @@ public static string[] GetImportedNamespaces(RefitGeneratorSettings settings)
.Where(n => !string.IsNullOrWhiteSpace(n))
.Select(x => new Regex(x, RegexOptions.Compiled))
.ToList();

var excludedNamespaces = exclusionNamespacesRegexes.SelectMany(k => namespaces.Where(x => k.IsMatch(x)));
namespaces = namespaces.Except(excludedNamespaces).ToList();
}
Expand All @@ -65,4 +60,4 @@ public static string GenerateNamespaceImports(RefitGeneratorSettings settings) =
GetImportedNamespaces(settings)
.Select(ns => $"using {ns};")
.Aggregate((a, b) => $"{a}{Environment.NewLine}{b}");
}
}
3 changes: 2 additions & 1 deletion src/Refitter.SourceGenerator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ The following is an example `.refitter` file
"^/store/.*"
],
"useDynamicQuerystringParameters": true, // Optional. Default=false
"usePolymorphicSerialization": false, // Optional. Default=false
"usePolymorphicSerialization": true, // Optional. Default=false
"generateDisposableClients": true, // Optional. Default=false
"dependencyInjectionSettings": { // Optional
"baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually
"httpMessageHandlers": [ // Optional
Expand Down
22 changes: 22 additions & 0 deletions src/Refitter.Tests/SwaggerPetstoreMultipleFileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,28 @@ await GenerateCode(
});
}

[Theory]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")]
#if !DEBUG
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")]
#endif
public async Task Can_Build_Generate_Code_With_IDisposable(SampleOpenSpecifications version, string filename)
{
await GenerateCode(
version,
filename,
new RefitGeneratorSettings { GenerateDisposableClients = true },
assert: generatorOutput =>
{
BuildHelper
.BuildCSharp(generatorOutput.Files.Select(code => code.Content).ToArray())
.Should()
.BeTrue();
});
}

private static async Task GenerateCode(
SampleOpenSpecifications version,
string filename,
Expand Down
36 changes: 33 additions & 3 deletions src/Refitter.Tests/SwaggerPetstoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ public async Task Can_Generate_Code_Dependency_Injection_Setup_Without_Polly(Sam
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")]
public async Task Can_Generate_Code_Apizr_Setup(SampleOpenSpecifications version, string filename)
{
var settings = new RefitGeneratorSettings
var settings = new RefitGeneratorSettings
{
DependencyInjectionSettings = new DependencyInjectionSettings
{
Expand Down Expand Up @@ -387,7 +387,7 @@ public async Task Can_Generate_Code_Apizr_Setup(SampleOpenSpecifications version
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")]
public async Task Can_Generate_Code_Apizr_Setup_With_Polly(SampleOpenSpecifications version, string filename)
{
var settings = new RefitGeneratorSettings
var settings = new RefitGeneratorSettings
{
DependencyInjectionSettings = new DependencyInjectionSettings
{
Expand Down Expand Up @@ -416,7 +416,7 @@ public async Task Can_Generate_Code_Apizr_Setup_With_Polly(SampleOpenSpecificati
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")]
public async Task Can_Generate_Code_Apizr_Setup_Without_Polly(SampleOpenSpecifications version, string filename)
{
var settings = new RefitGeneratorSettings
var settings = new RefitGeneratorSettings
{
DependencyInjectionSettings = new DependencyInjectionSettings
{
Expand Down Expand Up @@ -740,4 +740,34 @@ public async Task Can_Generate_Code_With_DynamicQuerystringParameters(SampleOpen
generateCode.Should().Contain("[Query] LoginUserQueryParams queryParams);")
.And.Contain("public class LoginUserQueryParams");
}

[Theory]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")]
public async Task Can_Generate_Code_With_IDisposable(SampleOpenSpecifications version, string filename)
{
var settings = new RefitGeneratorSettings { GenerateDisposableClients = true };
var generateCode = await GenerateCode(version, filename, settings);
generateCode.Should().Contain("IDisposable");
}

[Theory]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")]
#if !DEBUG
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")]
[InlineData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")]
#endif
public async Task Can_Build_Generated_Code_With_IDisposable(SampleOpenSpecifications version, string filename)
{
var settings = new RefitGeneratorSettings();
settings.GenerateDisposableClients = true;
var generateCode = await GenerateCode(version, filename, settings);
BuildHelper
.BuildCSharp(generateCode)
.Should()
.BeTrue();
}
}
1 change: 1 addition & 0 deletions src/Refitter/GenerateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ private static RefitGeneratorSettings CreateRefitGeneratorSettings(Settings sett
ContractsOutputFolder = settings.ContractsOutputPath ?? settings.OutputPath,
ContractsNamespace = settings.ContractsNamespace,
UsePolymorphicSerialization = settings.UsePolymorphicSerialization,
GenerateDisposableClients = settings.GenerateDisposableClients,
};
}

Expand Down
Loading

0 comments on commit 555d08c

Please sign in to comment.