Skip to content

Commit

Permalink
Merge pull request #188 from christianhelle/code-generator-settings
Browse files Browse the repository at this point in the history
Add support for customizable type and contract generator settings
  • Loading branch information
christianhelle committed Oct 12, 2023
2 parents e7fbb86 + e2c24b8 commit be561bb
Show file tree
Hide file tree
Showing 20 changed files with 921 additions and 170 deletions.
68 changes: 67 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ The following is an example `.refitter` file
"^/pet/.*",
"^/store/.*"
],
"dependencyInjectionSettings": {
"dependencyInjectionSettings": { // Optional
"baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually
"httpMessageHandlers": [ // Optional
"AuthorizationMessageHandler",
Expand All @@ -161,6 +161,41 @@ The following is an example `.refitter` file
"usePolly": true, // Optional. Set this to true, to configure Polly with a retry policy that uses a jittered backoff. Default=false
"pollyMaxRetryCount": 3, // Optional. Default=6
"firstBackoffRetryInSeconds": 0.5 // Optional. Default=1.0
},
"codeGeneratorSettings": { // Optional. Default settings are the values set in this example
"namespace": "GeneratedCode",
"requiredPropertiesMustBeDefined": true,
"generateDataAnnotations": true,
"anyType": "object",
"dateType": "System.DateTimeOffset",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"propertySetterAccessModifier": "",
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"handleReferences": false,
"jsonSerializerSettingsTransformationMethod": null,
"generateJsonMethods": false,
"enforceFlagEnums": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedArrays": false,
"generateOptionalPropertiesAsNullable": false,
"generateNullableReferenceTypes": false,
"generateNativeRecords": false,
"generateDefaultValues": true,
"inlineNamedAny": false,
"excludedTypeNames": [
"ExcludedTypeFoo",
"ExcludedTypeBar"
]
}
}
```
Expand Down Expand Up @@ -192,6 +227,37 @@ The following is an example `.refitter` file
- `usePolly` - Set this to true to configure the HttpClient to use Polly using a retry policy with a jittered backoff
- `pollyMaxRetryCount` - 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
- `codeGeneratorSettings` - Setting this allows customization of the NSwag generated types and contracts
- `namespace` - Default is `GeneratedCode`,
- `requiredPropertiesMustBeDefined` - Default is true,
- `generateDataAnnotations` - Default is true,
- `anyType` - Default is `object`,
- `dateType` - Default is `System.DateTimeOffset`,
- `dateTimeType` - Default is `System.DateTimeOffset`,
- `timeType` - Default is `System.TimeSpan`,
- `timeSpanType` - Default is `System.TimeSpan`,
- `arrayType` - Default is `System.Collections.Generic.ICollection`,
- `dictionaryType` - Default is `System.Collections.Generic.IDictionary`,
- `arrayInstanceType` - Default is `System.Collections.ObjectModel.Collection`,
- `dictionaryInstanceType` - Default is `System.Collections.Generic.Dictionary`,
- `arrayBaseType` - Default is `System.Collections.ObjectModel.Collection`,
- `dictionaryBaseType` - Default is `System.Collections.Generic.Dictionary`,
- `propertySetterAccessModifier` - Default is ``,
- `generateImmutableArrayProperties` - Default is false,
- `generateImmutableDictionaryProperties` - Default is false,
- `handleReferences` - Default is false,
- `jsonSerializerSettingsTransformationMethod` - Default is null,
- `generateJsonMethods` - Default is false,
- `enforceFlagEnums` - Default is false,
- `inlineNamedDictionaries` - Default is false,
- `inlineNamedTuples` - Default is true,
- `inlineNamedArrays` - Default is false,
- `generateOptionalPropertiesAsNullable` - Default is false,
- `generateNullableReferenceTypes` - Default is false,
- `generateNativeRecords` - Default is false
- `generateDefaultValues` - Default is true
- `inlineNamedAny` - Default is false
- `excludedTypeNames` - Default is empty


# Using the generated code
Expand Down
72 changes: 71 additions & 1 deletion docs/docfx_project/articles/refitter-file-format.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## .Refitter File format

The `.refitter` file is a JSON serialized version of the [RefitGeneratorSettings](/api/Refitter.Core.RefitGeneratorSettings.html)

The following is an example `.refitter` file

```js
Expand Down Expand Up @@ -46,10 +48,47 @@ The following is an example `.refitter` file
"usePolly": true, // Optional. Set this to true, to configure Polly with a retry policy that uses a jittered backoff. Default=false
"pollyMaxRetryCount": 3, // Optional. Default=6
"firstBackoffRetryInSeconds": 0.5 // Optional. Default=1.0
},
"codeGeneratorSettings": { // Optional. Default settings are the values set in this example
"namespace": "GeneratedCode",
"requiredPropertiesMustBeDefined": true,
"generateDataAnnotations": true,
"anyType": "object",
"dateType": "System.DateTimeOffset",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"propertySetterAccessModifier": "",
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"handleReferences": false,
"jsonSerializerSettingsTransformationMethod": null,
"generateJsonMethods": false,
"enforceFlagEnums": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedArrays": false,
"generateOptionalPropertiesAsNullable": false,
"generateNullableReferenceTypes": false,
"generateNativeRecords": false,
"generateDefaultValues": true,
"inlineNamedAny": false,
"excludedTypeNames": [
"ExcludedTypeFoo",
"ExcludedTypeBar"
]
}
}
```

Here are some basic explanations of each property:

- `openApiPath` - points to the OpenAPI Specifications file. This can be the path to a file stored on disk, relative to the `.refitter` file. This can also be a URL to a remote file that will be downloaded over HTTP/HTTPS
- `namespace` - the namespace used in the generated code. If not specified, this defaults to `GeneratedCode`
- `naming.useOpenApiTitle` - a boolean indicating whether the OpenApi title should be used. Default is `true`
Expand All @@ -76,4 +115,35 @@ The following is an example `.refitter` file
- `httpMessageHandlers` - A collection of `HttpMessageHandler` that is added to the HttpClient pipeline
- `usePolly` - Set this to true to configure the HttpClient to use Polly using a retry policy with a jittered backoff
- `pollyMaxRetryCount` - 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
- `firstBackoffRetryInSeconds` - This is the duration of the initial retry backoff. Default is 1 second
- `codeGeneratorSettings` - Setting this allows customization of the NSwag generated types and contracts
- `namespace` - Default is `GeneratedCode`,
- `requiredPropertiesMustBeDefined` - Default is true,
- `generateDataAnnotations` - Default is true,
- `anyType` - Default is `object`,
- `dateType` - Default is `System.DateTimeOffset`,
- `dateTimeType` - Default is `System.DateTimeOffset`,
- `timeType` - Default is `System.TimeSpan`,
- `timeSpanType` - Default is `System.TimeSpan`,
- `arrayType` - Default is `System.Collections.Generic.ICollection`,
- `dictionaryType` - Default is `System.Collections.Generic.IDictionary`,
- `arrayInstanceType` - Default is `System.Collections.ObjectModel.Collection`,
- `dictionaryInstanceType` - Default is `System.Collections.Generic.Dictionary`,
- `arrayBaseType` - Default is `System.Collections.ObjectModel.Collection`,
- `dictionaryBaseType` - Default is `System.Collections.Generic.Dictionary`,
- `propertySetterAccessModifier` - Default is ``,
- `generateImmutableArrayProperties` - Default is false,
- `generateImmutableDictionaryProperties` - Default is false,
- `handleReferences` - Default is false,
- `jsonSerializerSettingsTransformationMethod` - Default is null,
- `generateJsonMethods` - Default is false,
- `enforceFlagEnums` - Default is false,
- `inlineNamedDictionaries` - Default is false,
- `inlineNamedTuples` - Default is true,
- `inlineNamedArrays` - Default is false,
- `generateOptionalPropertiesAsNullable` - Default is false,
- `generateNullableReferenceTypes` - Default is false,
- `generateNativeRecords` - Default is false
- `generateDefaultValues` - Default is true
- `inlineNamedAny` - Default is false
- `excludedTypeNames` - Default is empty
85 changes: 64 additions & 21 deletions src/Refitter.Core/CSharpClientGeneratorFactory.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,79 @@
using System.Diagnostics;

using NJsonSchema.CodeGeneration.CSharp;

using NSwag;
using NSwag.CodeGeneration.CSharp;

namespace Refitter.Core;

internal class CSharpClientGeneratorFactory
internal class CSharpClientGeneratorFactory(RefitGeneratorSettings settings, OpenApiDocument document)
{
private readonly RefitGeneratorSettings settings;
private readonly OpenApiDocument document;

public CSharpClientGeneratorFactory(RefitGeneratorSettings settings, OpenApiDocument document)
public CustomCSharpClientGenerator Create()
{
this.settings = settings;
this.document = document;
var generator = new CustomCSharpClientGenerator(
document,
new CSharpClientGeneratorSettings
{
GenerateClientClasses = false,
GenerateDtoTypes = true,
GenerateClientInterfaces = false,
GenerateExceptionClasses = false,
CodeGeneratorSettings =
{
PropertyNameGenerator = new CustomCSharpPropertyNameGenerator(),
},
CSharpGeneratorSettings =
{
Namespace = settings.Namespace,
JsonLibrary = CSharpJsonLibrary.SystemTextJson,
TypeAccessModifier = settings.TypeAccessibility.ToString().ToLowerInvariant(),
}
});

MapCSharpGeneratorSettings(
settings.CodeGeneratorSettings,
generator.Settings.CSharpGeneratorSettings);

return generator;
}

public CustomCSharpClientGenerator Create() =>
new(document, new CSharpClientGeneratorSettings
private static void MapCSharpGeneratorSettings(
CodeGeneratorSettings? source,
CSharpGeneratorSettings destination)
{
if (source is null)
{
GenerateClientClasses = false,
GenerateDtoTypes = true,
GenerateClientInterfaces = false,
GenerateExceptionClasses = false,
CodeGeneratorSettings =
return;
}

var defaultInstance = new CodeGeneratorSettings();
foreach (var property in source.GetType().GetProperties())
{
if (property.PropertyType != typeof(string) &&
property.PropertyType != typeof(bool))
{
PropertyNameGenerator = new CustomCSharpPropertyNameGenerator(),
},
CSharpGeneratorSettings =
continue;
}

var value = property.GetValue(source);
if (value == null)
{
Namespace = settings.Namespace,
JsonLibrary = CSharpJsonLibrary.SystemTextJson,
TypeAccessModifier = settings.TypeAccessibility.ToString().ToLowerInvariant()
continue;
}
});

if (value.Equals(property.GetValue(defaultInstance)))
{
continue;
}

var settingsProperty = destination.GetType().GetProperty(property.Name);
if (settingsProperty == null)
{
continue;
}

settingsProperty.SetValue(destination, value);
}
}
}
34 changes: 34 additions & 0 deletions src/Refitter.Core/Serializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Text.Json;

using JsonSerializerOptions = System.Text.Json.JsonSerializerOptions;

namespace Refitter.Core;

/// <summary>
/// Provides methods for serializing and deserializing objects to and from JSON.
/// This serializer is configured to be case-insensitive.
/// </summary>
public static class Serializer
{
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true
};

/// <summary>
/// Deserializes the JSON string to the specified type.
/// </summary>
/// <typeparam name="T">The type to deserialize the JSON string to.</typeparam>
/// <param name="json">The JSON string to deserialize.</param>
/// <returns>The deserialized object of type T.</returns>
public static T Deserialize<T>(string json) =>
JsonSerializer.Deserialize<T>(json, JsonSerializerOptions)!;

/// <summary>
/// Serializes the specified object to a JSON string.
/// </summary>
/// <param name="any">The object to serialize.</param>
/// <returns>The JSON string representation of the object.</returns>
public static string Serialize(object any) =>
JsonSerializer.Serialize(any, JsonSerializerOptions);
}
Loading

0 comments on commit be561bb

Please sign in to comment.