Skip to content

Commit

Permalink
Allow endpoints to be excluded by path and/or by deprecated
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielKStan committed Dec 29, 2024
1 parent 8369a99 commit 481e230
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 6 deletions.
52 changes: 52 additions & 0 deletions src/NSwag.CodeGeneration.CSharp.Tests/CSharpClientSettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ public class CSharpClientSettingsTests
{
public class FooController : Controller
{
#pragma warning disable S1133 // Deprecated code should be removed
[Obsolete("Testing generation of obsolete endpoints")]
#pragma warning restore S1133 // Deprecated code should be removed
public object GetPerson(bool @override = false)
{
return null;
Expand Down Expand Up @@ -104,6 +107,7 @@ public async Task When_parameter_name_is_reserved_keyword_then_it_is_appended_wi

// Assert
Assert.Contains("Task<object> GetPersonAsync(bool? @override, ", code);
Assert.Contains("Obsolete", code);
}

[Fact]
Expand Down Expand Up @@ -247,5 +251,53 @@ public async Task When_client_interface_generation_is_enabled_and_suppressed_the
Assert.DoesNotContain("public partial interface IFooClient", code);
Assert.Contains("public partial class FooClient : IFooClient", code);
}

[Fact]
public async Task When_regex_is_set_to_excluded_endpoints_the_client_will_not_generate_these_endpoint()
{
// Arrange
var swaggerGenerator = new WebApiOpenApiDocumentGenerator(new WebApiOpenApiDocumentGeneratorSettings
{
SchemaSettings = new NewtonsoftJsonSchemaGeneratorSettings()
});

var document = await swaggerGenerator.GenerateForControllerAsync<FooController>();
string firstPath = document.Paths.Keys.First();
var generator = new CSharpClientGenerator(document, new CSharpClientGeneratorSettings
{
GenerateClientClasses = true,
ExcludeByPathRegex = firstPath.Replace("/", "\\/").TrimStart('/') // path: "/api/Foo" so corresponding regex is "api\/Foo"
});

// Act
var code = generator.GenerateFile();

// Assert
Assert.DoesNotContain("GetPerson", code);
}

[Fact]
public async Task When_depreacted_endpoints_are_excluded_the_client_will_not_generate_these_endpoint()
{
// Arrange
var swaggerGenerator = new WebApiOpenApiDocumentGenerator(new WebApiOpenApiDocumentGeneratorSettings
{
SchemaSettings = new NewtonsoftJsonSchemaGeneratorSettings()
});

var document = await swaggerGenerator.GenerateForControllerAsync<FooController>();
var generator = new CSharpClientGenerator(document, new CSharpClientGeneratorSettings
{
GenerateClientClasses = true,
ExcludeDeprecated = true
});

// Act
var code = generator.GenerateFile();

// Assert
Assert.DoesNotContain("GetPerson", code);
Assert.DoesNotContain("Obsolete", code);
}
}
}
13 changes: 12 additions & 1 deletion src/NSwag.CodeGeneration/ClientGeneratorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using NJsonSchema;
using NJsonSchema.CodeGeneration;
using NSwag.CodeGeneration.Models;
using System.Text.RegularExpressions;

namespace NSwag.CodeGeneration
{
Expand Down Expand Up @@ -162,6 +163,17 @@ private List<TOperationModel> GetOperations(OpenApiDocument document)
var httpMethod = p.Key;
var operation = p.Value;

if (this.BaseSettings.ExcludeDeprecated && operation.IsDeprecated)
{
continue;
}

if (!string.IsNullOrWhiteSpace(this.BaseSettings.ExcludeByPathRegex) && Regex.IsMatch(pair.Key, this.BaseSettings.ExcludeByPathRegex))
{
continue;
}


var operationName =
BaseSettings.OperationNameGenerator.GetOperationName(document, path, httpMethod, operation);

Expand All @@ -181,7 +193,6 @@ private List<TOperationModel> GetOperations(OpenApiDocument document)
operationModel.Path = path;
operationModel.HttpMethod = httpMethod;
operationModel.OperationName = operationName;

result.Add(operationModel);
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/NSwag.CodeGeneration/ClientGeneratorBaseSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,16 @@ public virtual string GenerateControllerName(string controllerName)

/// <summary>Gets or sets the name of the response class (supports the '{controller}' placeholder).</summary>
public string ResponseClass { get; set; }

//-------
/// <summary>Gets or sets the value indicating if deprecated endpoints shall be rendered</summary>
public bool ExcludeDeprecated { get; set; }

/// <summary>Gets or sets the regular expression to indicate for which path's client code should be generated (null/empty means all)</summary>
public string ExcludeByPathRegex { get; set; }




}
}
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,20 @@ public string QueryNullValue
set => Settings.QueryNullValue = value;
}

[Argument(Name = "ExcludeDeprecated", IsRequired = false, Description = "Specifies if deprecated endpoints should be generated")]
public bool ExcludeDeprecated
{
get { return Settings.ExcludeDeprecated; }
set { Settings.ExcludeDeprecated = value; }
}

[Argument(Name = "ExcludeByPathRegex", IsRequired = false, Description = "The regex which defines endpoints should not be genereated (regex is applied to path)")]
public string ExcludeByPathRegex
{
get { return Settings.ExcludeByPathRegex; }
set { Settings.ExcludeByPathRegex = value; }
}

public override async Task<object> RunAsync(CommandLineProcessor processor, IConsoleHost host)
{
var result = await RunAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,20 @@ public bool IncludeHttpContext
set => Settings.IncludeHttpContext = value;
}

[Argument(Name = "ExcludeDeprecated", IsRequired = false, Description = "Specifies if deprecated endpoints should be generated")]
public bool ExcludeDeprecated
{
get { return Settings.ExcludeDeprecated; }
set { Settings.ExcludeDeprecated = value; }
}

[Argument(Name = "ExcludeByPathRegex", IsRequired = false, Description = "The regex which defines endpoints should not be genereated (regex is applied to path)")]
public string ExcludeByPathRegex
{
get { return Settings.ExcludeByPathRegex; }
set { Settings.ExcludeByPathRegex = value; }
}

public override async Task<object> RunAsync(CommandLineProcessor processor, IConsoleHost host)
{
var code = await RunAsync();
Expand Down
4 changes: 4 additions & 0 deletions src/NSwag.Sample.NET80Minimal/nswag.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@
"inlineNamedDictionaries": false,
"inlineNamedAny": false,
"includeHttpContext": false,
"excludeDeprecated": false,
"excludeByPathRegex": null,
"templateDirectory": null,
"serviceHost": null,
"serviceSchemes": null,
Expand Down Expand Up @@ -114,6 +116,8 @@
"useRequestAndResponseSerializationSettings": false,
"serializeTypeInformation": false,
"queryNullValue": "",
"excludeDeprecated": false,
"excludeByPathRegex": null,
"className": "{controller}Client",
"operationGenerationMode": "MultipleClientsFromOperationId",
"additionalNamespaceUsages": [],
Expand Down
4 changes: 4 additions & 0 deletions src/NSwag.Sample.NET90Minimal/nswag.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@
"inlineNamedDictionaries": false,
"inlineNamedAny": false,
"includeHttpContext": false,
"excludeDeprecated": false,
"excludeByPathRegex": null,
"templateDirectory": null,
"serviceHost": null,
"serviceSchemes": null,
Expand Down Expand Up @@ -114,6 +116,8 @@
"useRequestAndResponseSerializationSettings": false,
"serializeTypeInformation": false,
"queryNullValue": "",
"excludeDeprecated": false,
"excludeByPathRegex": null,
"className": "{controller}Client",
"operationGenerationMode": "MultipleClientsFromOperationId",
"additionalNamespaceUsages": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@
ToolTip="AdditionalNamespaceUsages"
Margin="0,0,0,12" />

<CheckBox IsChecked="{Binding Command.GenerateContractsOutput, Mode=TwoWay}"
ToolTip="GenerateContractsOutput"
Content="Generate contracts output"
Margin="0,0,0,12" />

<CheckBox IsChecked="{Binding Command.GenerateNativeRecords, Mode=TwoWay}"
ToolTip="GenerateNativeRecords"
Content="Generate record types"
Margin="0,0,0,12" />

<CheckBox IsChecked="{Binding Command.GenerateContractsOutput, Mode=TwoWay}"
ToolTip="GenerateContractsOutput"
Content="Generate contracts output"
Margin="0,0,0,12" />

<StackPanel Visibility="{Binding Command.GenerateContractsOutput, Converter={StaticResource VisibilityConverter}}">
<TextBlock Text="Contracts Namespace"
Expand Down Expand Up @@ -162,6 +162,19 @@
ToolTip="SuppressClientInterfacesOutput"
Content="Suppress output of generated interfaces for Client classes" Margin="0,0,0,12" />

<CheckBox IsChecked="{Binding Command.ExcludeDeprecated, Mode=TwoWay}"
Content="Exclude deprecated endpoints"
ToolTip="ExcludeDeprecated"
Margin="0,0,0,12" />

<TextBlock Text="Exclude the following endpoints by their path (via Regex)"
FontWeight="Bold"
Margin="0,0,0,6" />

<TextBox Text="{Binding Command.ExcludeByPathRegex, Mode=TwoWay}"
ToolTip="ExcludeByPathRegex"
Margin="0,0,0,12" />

<TextBlock Text="Base interface for Client Interfaces (optional)" FontWeight="Bold" Margin="0,0,0,6"
Visibility="{Binding Command.GenerateClientInterfaces, Converter={StaticResource VisibilityConverter}}" />
<TextBox Text="{Binding Command.ClientBaseInterface, Mode=TwoWay}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,18 @@
<TextBox ToolTip="ProtectedMethods"
Text="{Binding Command.ProtectedMethods, Mode=TwoWay, Converter={StaticResource StringArrayConverter}, ConverterParameter=','}"
Margin="0,0,0,12" />

<CheckBox IsChecked="{Binding Command.ExcludeDeprecated, Mode=TwoWay}"
Content="Exclude deprecated endpoints"
ToolTip="ExcludeDeprecated"
Margin="0,0,0,12" />

<TextBlock Text="Exclude the following endpoints by their path (via Regex)"
FontWeight="Bold"
Margin="0,0,0,6" />
<TextBox Text="{Binding Command.ExcludeByPathRegex, Mode=TwoWay}"
ToolTip="ExcludeByPathRegex"
Margin="0,0,0,12" />
</StackPanel>
</StackPanel>
</GroupBox>
Expand Down

0 comments on commit 481e230

Please sign in to comment.