Skip to content

Commit

Permalink
Merge pull request #428 from Respawnsive/apizr
Browse files Browse the repository at this point in the history
Add the possibility to generate all the Apizr goodness
  • Loading branch information
christianhelle authored Jul 25, 2024
2 parents 48f66f8 + a4d3a0a commit e7c1b4b
Show file tree
Hide file tree
Showing 21 changed files with 1,393 additions and 9 deletions.
618 changes: 618 additions & 0 deletions src/Refitter.Core/ApizrRegistrationGenerator.cs

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions src/Refitter.Core/EnumExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Reflection;

namespace Refitter.Core
{
internal static class EnumExtensions
{
private static readonly ConcurrentDictionary<string, string> DescriptionCache = new();

public static string ToDescription(this Enum value)
{
var key = $"{value.GetType().FullName}.{value}";

var displayName = DescriptionCache.GetOrAdd(key, _ =>
{
var name = (DescriptionAttribute[])value!
.GetType()!
.GetTypeInfo()!
.GetField(value.ToString())!
.GetCustomAttributes(typeof(DescriptionAttribute), false);

return name.Length > 0 ? name[0].Description : value.ToString();
});

return displayName;
}
}
}
6 changes: 4 additions & 2 deletions src/Refitter.Core/ParameterExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ public static IEnumerable<string> GetParameters(

parameters = ReOrderNullableParameters(parameters, settings);

if (settings.UseCancellationTokens)
if (settings.ApizrSettings?.WithRequestOptions == true)
parameters.Add("[RequestOptions] IApizrRequestOptions options");
else if (settings.UseCancellationTokens)
parameters.Add("CancellationToken cancellationToken = default");

return parameters;
Expand All @@ -70,7 +72,7 @@ private static List<string> ReOrderNullableParameters(
List<string> parameters,
RefitGeneratorSettings settings)
{
if (!settings.OptionalParameters)
if (!settings.OptionalParameters || settings.ApizrSettings?.WithRequestOptions == true)
return parameters;

parameters = parameters.OrderBy(c => c.Contains("?")).ToList();
Expand Down
7 changes: 6 additions & 1 deletion src/Refitter.Core/RefitGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,16 @@ public string Generate()
};

var generatedCode = GenerateClient(interfaceGenerator);
var title = settings.Naming.UseOpenApiTitle && !string.IsNullOrWhiteSpace(document.Info?.Title)
? document.Info!.Title.Sanitize()
: settings.Naming.InterfaceName;
return new StringBuilder()
.AppendLine(generatedCode.SourceCode)
.AppendLine()
.AppendLine(settings.GenerateContracts ? contracts : string.Empty)
.AppendLine(DependencyInjectionGenerator.Generate(settings, generatedCode.InterfaceNames))
.AppendLine(settings.ApizrSettings != null
? ApizrRegistrationGenerator.Generate(settings, generatedCode.InterfaceNames, title)
: DependencyInjectionGenerator.Generate(settings, generatedCode.InterfaceNames))
.ToString()
.TrimEnd();
}
Expand Down
32 changes: 31 additions & 1 deletion src/Refitter.Core/RefitInterfaceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private string GenerateInterfaceBody()
var name = GenerateOperationName(kv.Key, verb, operation);

var operationModel = generator.CreateOperationModel(operation);
var parameters = ParameterExtractor.GetParameters(operationModel, operation, settings);
var parameters = ParameterExtractor.GetParameters(operationModel, operation, settings).ToList();
var parametersString = string.Join(", ", parameters);

this.docGenerator.AppendMethodDocumentation(operationModel, IsApiResponseType(returnType), code);
Expand All @@ -70,6 +70,36 @@ private string GenerateInterfaceBody()
code.AppendLine($"{Separator}{Separator}[{verb}(\"{kv.Key}\")]")
.AppendLine($"{Separator}{Separator}{returnType} {name}({parametersString});")
.AppendLine();

if (settings is {OptionalParameters: true, ApizrSettings: { WithRequestOptions: true }})
{
var optionalParameterIndices = parameters
.Select((parameter, index) => (parameter, index))
.Where(x => x.parameter.Contains("?"))
.Select(x => x.index)
.ToList();
if (optionalParameterIndices.Count > 0)
{
var operationParametersToRemove = operationModel.Parameters.Where((_, index) => optionalParameterIndices.Contains(index)).ToList();
foreach (var operationParameterToRemove in operationParametersToRemove)
operationModel.Parameters.Remove(operationParameterToRemove);

this.docGenerator.AppendMethodDocumentation(operationModel, IsApiResponseType(returnType), code);
GenerateObsoleteAttribute(operation, code);
GenerateForMultipartFormData(operationModel, code);
GenerateAcceptHeaders(operations, operation, code);

var parametersToRemove = parameters.Where((_, index) => optionalParameterIndices.Contains(index)).ToList();
foreach (string parameterToRemove in parametersToRemove)
parameters.Remove(parameterToRemove);

parametersString = string.Join(", ", parameters);

code.AppendLine($"{Separator}{Separator}[{verb}(\"{kv.Key}\")]")
.AppendLine($"{Separator}{Separator}{returnType} {name}({parametersString});")
.AppendLine();
}
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/Refitter.Core/RefitInterfaceImports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ internal static class RefitInterfaceImports
public static string[] GetImportedNamespaces(RefitGeneratorSettings settings)
{
var namespaces = new List<string>(defaultNamespases);
if (settings.UseCancellationTokens)
if (settings.ApizrSettings?.WithRequestOptions == true)
{
namespaces.Add("Apizr.Configuring.Request");
}
else if (settings.UseCancellationTokens)
{
namespaces.Add("System.Threading");
}
Expand Down
52 changes: 52 additions & 0 deletions src/Refitter.Core/Settings/ApizrPackages.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace Refitter.Core.Settings
{
public enum ApizrPackages
{
[Description("dotnet add package Apizr")]
Apizr = 1,

[Description("dotnet add package Apizr.Extensions.Microsoft.DependencyInjection")]
Apizr_Extensions_Microsoft_DependencyInjection = 2 | Apizr,

[Description("dotnet add package Apizr.Integrations.Akavache")]
Apizr_Integrations_Akavache = 4 | Apizr,

[Description("dotnet add package Apizr.Integrations.MonkeyCache, then write somewhere: Barrel.ApplicationId = \"YOUR_APPLICATION_NAME\";")]
Apizr_Integrations_MonkeyCache = 8 | Apizr,

[Description("dotnet add package Apizr.Integrations.Fusillade")]
Apizr_Integrations_Fusillade = 16 | Apizr,

[Description("dotnet add package Apizr.Integrations.AutoMapper, then register AutoMapper")]
Apizr_Integrations_AutoMapper = 32 | Apizr,

[Description("dotnet add package Apizr.Integrations.Mapster, then register Mapster")]
Apizr_Integrations_Mapster = 64 | Apizr,

[Description("dotnet add package Apizr.Integrations.FileTransfer")]
Apizr_Integrations_FileTransfer = 128 | Apizr,

[Description("dotnet add package Apizr.Extensions.Microsoft.Caching, then register your caching provider")]
Apizr_Extensions_Microsoft_Caching = 256 | Apizr_Extensions_Microsoft_DependencyInjection,

[Description("dotnet add package Apizr.Extensions.Microsoft.FileTransfer")]
Apizr_Extensions_Microsoft_FileTransfer = 512 | Apizr_Integrations_FileTransfer | Apizr_Extensions_Microsoft_DependencyInjection,

[Description("dotnet add package Apizr.Integrations.MediatR, then register MediatR")]
Apizr_Integrations_MediatR = 1024 | Apizr_Extensions_Microsoft_DependencyInjection,

[Description("dotnet add package Apizr.Integrations.FileTransfer.MediatR, then register MediatR")]
Apizr_Integrations_FileTransfer_MediatR = 2048 | Apizr_Integrations_MediatR | Apizr_Extensions_Microsoft_FileTransfer,

[Description("dotnet add package Apizr.Integrations.Optional, then register MediatR")]
Apizr_Integrations_Optional = 4096 | Apizr_Integrations_MediatR,

[Description("dotnet add package Apizr.Integrations.FileTransfer.Optional, then register MediatR")]
Apizr_Integrations_FileTransfer_Optional = 8192 | Apizr_Integrations_Optional | Apizr_Integrations_FileTransfer_MediatR,
}
}
68 changes: 68 additions & 0 deletions src/Refitter.Core/Settings/ApizrSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;

namespace Refitter.Core
{
/// <summary>
/// Describing how Apizr should be configured.
/// Here are only the common configurations.
/// </summary>
public class ApizrSettings
{
/// <summary>
/// Set it to true to include an Apizr Request Options parameter into all api methods
/// and get all the Apizr goodness (default: true)
/// </summary>
public bool WithRequestOptions { get; set; } = true;

/// <summary>
/// Set it to true to generate an Apizr registration helper ready to use (default: false).
/// Please note that it will generate an extended or static helper depending on DependencyInjectionSettings property value.
/// </summary>
public bool WithRegistrationHelper { get; set; } = false;

/// <summary>
/// Library to use for cache handling (default: None)
/// Options:
/// - None
/// - Akavache
/// - MonkeyCache
/// - InMemory (Microsoft.Extensions.Caching.Memory)
/// - Distributed (Microsoft.Extensions.Caching.Distributed)
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public CacheProviderType WithCacheProvider { get; set; }

/// <summary>
/// Library to use for data mapping handling (default: None)
/// Options:
/// - None
/// - AutoMapper
/// - Mapster
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public MappingProviderType WithMappingProvider { get; set; }

/// <summary>
/// Set it to true to handle request with priority (default: false)
/// </summary>
public bool WithPriority { get; set; } = false;

/// <summary>
/// Set it to true to handle request with MediatR (default: false)
/// </summary>
public bool WithMediation { get; set; } = false;

/// <summary>
/// Set it to true to handle request with MediatR and Optional result (default: false)
/// </summary>
public bool WithOptionalMediation { get; set; } = false;

/// <summary>
/// Set it to true to manage file transfers (default: false)
/// </summary>
public bool WithFileTransfer { get; set; } = false;
}
}
12 changes: 12 additions & 0 deletions src/Refitter.Core/Settings/CacheProviderType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Refitter.Core
{
public enum CacheProviderType
{
None,
Akavache,
MonkeyCache,
InMemory,
DistributedAsString,
DistributedAsByteArray,
}
}
6 changes: 4 additions & 2 deletions src/Refitter.Core/Settings/DependencyInjectionSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace Refitter.Core;
/// </summary>
public class DependencyInjectionSettings
{
public const string DefaultExtensionMethodName = "ConfigureRefitClients";

/// <summary>
/// Base Address for the HttpClient
/// </summary>
Expand Down Expand Up @@ -62,7 +64,7 @@ public int PollyMaxRetryCount
public double FirstBackoffRetryInSeconds { get; set; } = 1.0;

/// <summary>
/// Name of IServiceCollection Extension Method. Default is ConfigureRefitClients
/// Name of IServiceCollection Extension Method. Default is ConfigureRefitClients, or ConfigureApizrManagers if ApizrSettings property is set
/// </summary>
public string ExtensionMethodName { get; set; } = "ConfigureRefitClients";
public string ExtensionMethodName { get; set; } = DefaultExtensionMethodName;
}
9 changes: 9 additions & 0 deletions src/Refitter.Core/Settings/MappingProviderType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Refitter.Core
{
public enum MappingProviderType
{
None,
AutoMapper,
Mapster
}
}
4 changes: 3 additions & 1 deletion src/Refitter.Core/Settings/NamingSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace Refitter.Core;
[ExcludeFromCodeCoverage]
public class NamingSettings
{
public const string DefaultInterfaceName = "ApiClient";

/// <summary>
/// Gets or sets a value indicating whether the OpenApi title should be used. Default is true.
/// </summary>
Expand All @@ -16,5 +18,5 @@ public class NamingSettings
/// <summary>
/// Gets or sets the name of the Interface. Default is "ApiClient".
/// </summary>
public string InterfaceName { get; set; } = "ApiClient";
public string InterfaceName { get; set; } = DefaultInterfaceName;
}
5 changes: 5 additions & 0 deletions src/Refitter.Core/Settings/RefitGeneratorSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,9 @@ public class RefitGeneratorSettings
/// Set to <c>true</c> to generate contracts as immutable records instead of classes
/// </summary>
public bool ImmutableRecords { get; set; }

/// <summary>
/// Get ot set the settings describing how to configure Apizr
/// </summary>
public ApizrSettings? ApizrSettings { get; set; }
}
Loading

0 comments on commit e7c1b4b

Please sign in to comment.