Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate IDisposable Refit Interfaces #543

Merged
merged 6 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading