Skip to content

Commit

Permalink
Merge pull request #193 from atc-net/feature/CustomErrorResponseModel
Browse files Browse the repository at this point in the history
Feature/custom error response model
  • Loading branch information
davidkallesen authored Jul 1, 2024
2 parents 8e76ed9 + 3f38790 commit fcd7780
Show file tree
Hide file tree
Showing 826 changed files with 45,483 additions and 214 deletions.
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@
<ItemGroup Label="Code Analyzers">
<PackageReference Include="AsyncFixer" Version="1.6.0" PrivateAssets="All" />
<PackageReference Include="Asyncify" Version="0.9.7" PrivateAssets="All" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.158" PrivateAssets="All" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.159" PrivateAssets="All" />
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.7" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.27.0.93347" PrivateAssets="All" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.28.0.94264" PrivateAssets="All" />
</ItemGroup>

</Project>
6 changes: 0 additions & 6 deletions atc-coding-rules-updater.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@
"temporarySuppressionAsExcel": false,
"analyzerProviderCollectingMode": "LocalCache",
"mappings": {
"sample": {
"paths": [
"sample-minimal",
"sample-mvc"
]
},
"src": {
"paths": [
"src"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Atc" Version="2.0.488" />
<PackageReference Include="Atc.CodeDocumentation" Version="2.0.488" />
<PackageReference Include="Atc" Version="2.0.490" />
<PackageReference Include="Atc.CodeDocumentation" Version="2.0.490" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ public string GenerateProperty(
{
if (!parameters.IsGenericListType &&
parameters.TypeName.Equals("string", StringComparison.Ordinal) &&
!parameters.DefaultValue.Equals("null", StringComparison.Ordinal))
!parameters.DefaultValue.Equals("null", StringComparison.Ordinal) &&
!parameters.DefaultValue.Equals("string.Empty", StringComparison.Ordinal))
{
sb.Append($" = \"{parameters.DefaultValue}\";");
}
Expand Down
118 changes: 74 additions & 44 deletions src/Atc.Rest.ApiGenerator.CLI/ApiOptionsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static async Task<ApiOptions> CreateDefault(
var options = await CreateDefault(optionsPath);

ApplyValidationOverrides(options, settings);
ApplyGeneratorOverrides(options, settings);

return options;
}
Expand All @@ -51,14 +52,14 @@ public static async Task<ApiOptions> CreateDefault(
{
ArgumentNullException.ThrowIfNull(optionsPath);

var options = new ApiOptions();

var fileInfo = GetOptionsFile(optionsPath);
if (fileInfo.Exists)
{
return (false, "File already exist");
options = await FileHelper<ApiOptions>.ReadJsonFileAndDeserializeAsync(fileInfo) ?? new ApiOptions();
}

var options = new ApiOptions();

await FileHelper<ApiOptions>.WriteModelToJsonFileAsync(fileInfo, options);
return (true, string.Empty);
}
Expand All @@ -74,10 +75,17 @@ public static async Task<ApiOptions> CreateDefault(
return (false, "File does not exist");
}

var options = await FileHelper<ApiOptions>.ReadJsonFileAndDeserializeAsync(fileInfo);
return options is null
? (false, "File is invalid")
: (true, string.Empty);
try
{
var options = await FileHelper<ApiOptions>.ReadJsonFileAndDeserializeAsync(fileInfo);
return options is null
? (false, "File is invalid")
: (true, string.Empty);
}
catch (Exception ex)
{
return (false, $"File is invalid: {ex.Message}");
}
}

private static FileInfo GetOptionsFile(
Expand Down Expand Up @@ -116,67 +124,89 @@ private static void ApplyValidationOverrides(
{
apiOptions.Validation.ModelPropertyNameCasingStyle = settings.ModelPropertyNameCasingStyle.Value;
}
}

private static void ApplyGeneratorOverrides(
ApiOptions apiOptions,
BaseConfigurationCommandSettings settings)
{
if (settings is BaseServerCommandSettings serverSettings)
{
if (serverSettings.AspNetOutputType.IsSet)
{
apiOptions.Generator.AspNetOutputType = serverSettings.AspNetOutputType.Value;
}

if (serverSettings.SwaggerThemeMode.IsSet)
{
apiOptions.Generator.SwaggerThemeMode = serverSettings.SwaggerThemeMode.Value;
}

if (serverSettings.UseProblemDetailsAsDefaultResponseBody)
{
apiOptions.Generator.Response.UseProblemDetailsAsDefaultBody = serverSettings.UseProblemDetailsAsDefaultResponseBody;
}

if (serverSettings.ProjectPrefixName is not null)
{
apiOptions.Generator.ProjectName = serverSettings.ProjectPrefixName
.Replace(" ", ".", StringComparison.Ordinal)
.Replace("-", ".", StringComparison.Ordinal)
.Trim();
}

apiOptions.Generator.RemoveNamespaceGroupSeparatorInGlobalUsings = serverSettings.RemoveNamespaceGroupSeparatorInGlobalUsings;
}

switch (settings)
{
case ServerAllCommandSettings serverAllCommandSettings:
case ClientApiCommandSettings clientApiCommandSettings:
{
if (serverAllCommandSettings.AspNetOutputType.IsSet)
if (clientApiCommandSettings.UseProblemDetailsAsDefaultResponseBody)
{
apiOptions.Generator.AspNetOutputType = serverAllCommandSettings.AspNetOutputType.Value;
apiOptions.Generator.Response.UseProblemDetailsAsDefaultBody = clientApiCommandSettings.UseProblemDetailsAsDefaultResponseBody;
}

if (serverAllCommandSettings.SwaggerThemeMode.IsSet)
if (clientApiCommandSettings.ProjectPrefixName is not null)
{
apiOptions.Generator.SwaggerThemeMode = serverAllCommandSettings.SwaggerThemeMode.Value;
apiOptions.Generator.ProjectName = clientApiCommandSettings.ProjectPrefixName;
}

if (serverAllCommandSettings.UseProblemDetailsAsDefaultResponseBody)
{
apiOptions.Generator.Response.UseProblemDetailsAsDefaultBody = serverAllCommandSettings.UseProblemDetailsAsDefaultResponseBody;
}
apiOptions.Generator.RemoveNamespaceGroupSeparatorInGlobalUsings = clientApiCommandSettings.RemoveNamespaceGroupSeparatorInGlobalUsings;

break;
}
case ServerHostCommandSettings serverHostCommandSettings:
{
if (serverHostCommandSettings.AspNetOutputType.IsSet)
if (string.IsNullOrEmpty(apiOptions.Generator.ProjectSuffixName))
{
apiOptions.Generator.AspNetOutputType = serverHostCommandSettings.AspNetOutputType.Value;
apiOptions.Generator.ProjectSuffixName = "ApiClient.Generated";
}

if (serverHostCommandSettings.SwaggerThemeMode.IsSet)
else
{
apiOptions.Generator.SwaggerThemeMode = serverHostCommandSettings.SwaggerThemeMode.Value;
apiOptions.Generator.ProjectSuffixName = apiOptions.Generator.ProjectSuffixName
.Replace(" ", ".", StringComparison.Ordinal)
.Replace("-", ".", StringComparison.Ordinal)
.Trim();
}

if (serverHostCommandSettings.UseProblemDetailsAsDefaultResponseBody)
apiOptions.Generator.Client ??= new ApiOptionsGeneratorClient();

if (clientApiCommandSettings.ClientFolderName is not null &&
clientApiCommandSettings.ClientFolderName.IsSet)
{
apiOptions.Generator.Response.UseProblemDetailsAsDefaultBody = serverHostCommandSettings.UseProblemDetailsAsDefaultResponseBody;
apiOptions.Generator.Client.FolderName = clientApiCommandSettings.ClientFolderName.Value;
}

break;
}
case ServerApiCommandSettings serverApiCommandSettings:
{
if (serverApiCommandSettings.UseProblemDetailsAsDefaultResponseBody)
if (clientApiCommandSettings.HttpClientName is not null &&
clientApiCommandSettings.HttpClientName.IsSet)
{
apiOptions.Generator.Response.UseProblemDetailsAsDefaultBody = serverApiCommandSettings.UseProblemDetailsAsDefaultResponseBody;
apiOptions.Generator.Client.HttpClientName = clientApiCommandSettings.HttpClientName.Value;
}

break;
}
case ServerDomainCommandSettings:
{
break;
}
case ClientApiCommandSettings clientApiCommandSettings:
{
if (clientApiCommandSettings.UseProblemDetailsAsDefaultResponseBody)
else
{
apiOptions.Generator.Response.UseProblemDetailsAsDefaultBody = clientApiCommandSettings.UseProblemDetailsAsDefaultResponseBody;
var baseGenerateCommandSettings = (BaseGenerateCommandSettings)settings;
apiOptions.Generator.Client.HttpClientName = $"{baseGenerateCommandSettings.ProjectPrefixName}-ApiClient";
}

apiOptions.Generator.Client.ExcludeEndpointGeneration = clientApiCommandSettings.ExcludeEndpointGeneration;

break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Atc" Version="2.0.488" />
<PackageReference Include="Atc.Console.Spectre" Version="2.0.488" />
<PackageReference Include="Atc" Version="2.0.490" />
<PackageReference Include="Atc.Console.Spectre" Version="2.0.490" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ private async Task<int> ExecuteInternalAsync(
var shouldScaffoldCodingRules = CodingRulesHelper.ShouldScaffoldCodingRules(settings.OutputPath, settings.DisableCodingRules);
var isUsingCodingRules = CodingRulesHelper.IsUsingCodingRules(settings.OutputPath, settings.DisableCodingRules);

var httpClientName = settings.HttpClientName is not null && settings.HttpClientName.IsSet
? settings.HttpClientName.Value
: null;

if (shouldScaffoldCodingRules &&
!NetworkInformationHelper.HasHttpConnection())
{
Expand All @@ -74,15 +70,10 @@ private async Task<int> ExecuteInternalAsync(
loggerFactory,
apiOperationExtractor,
nugetPackageReferenceProvider,
settings.ProjectPrefixName,
httpClientName,
settings.ClientFolderName is not null && settings.ClientFolderName.IsSet ? settings.ClientFolderName.Value : string.Empty,
new DirectoryInfo(settings.OutputPath),
apiDocumentContainer,
settings.ExcludeEndpointGeneration,
apiOptions,
isUsingCodingRules,
settings.RemoveNamespaceGroupSeparatorInGlobalUsings))
isUsingCodingRules))
{
return ConsoleExitStatusCodes.Failure;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@ public class ContentGeneratorClientEndpoint : IContentGenerator
private readonly CodeDocumentationTagsGenerator codeDocumentationTagsGenerator;
private readonly ContentGeneratorClientEndpointParameters parameters;
private readonly bool useProblemDetailsAsDefaultResponseBody;
private readonly string? customErrorResponseModel;

public ContentGeneratorClientEndpoint(
GeneratedCodeHeaderGenerator codeHeaderGenerator,
GeneratedCodeAttributeGenerator codeAttributeGenerator,
CodeDocumentationTagsGenerator codeDocumentationTagsGenerator,
ContentGeneratorClientEndpointParameters parameters,
bool useProblemDetailsAsDefaultResponseBody)
bool useProblemDetailsAsDefaultResponseBody,
string? customErrorResponseModel)
{
this.codeHeaderGenerator = codeHeaderGenerator;
this.codeAttributeGenerator = codeAttributeGenerator;
this.codeDocumentationTagsGenerator = codeDocumentationTagsGenerator;
this.parameters = parameters;
this.useProblemDetailsAsDefaultResponseBody = useProblemDetailsAsDefaultResponseBody;
this.customErrorResponseModel = customErrorResponseModel;
}

public string Generate()
Expand Down Expand Up @@ -115,7 +118,15 @@ public string Generate()
AppendAddSuccessResponseForStatusCodeOk(sb, responseModel);
break;
case HttpStatusCode.BadRequest:
sb.AppendLine(8, $"responseBuilder.AddErrorResponse<ValidationProblemDetails>(HttpStatusCode.{responseModel.StatusCode.ToNormalizedString()});");
if (string.IsNullOrEmpty(customErrorResponseModel))
{
sb.AppendLine(8, $"responseBuilder.AddErrorResponse<ValidationProblemDetails>(HttpStatusCode.{responseModel.StatusCode.ToNormalizedString()});");
}
else
{
sb.AppendLine(8, $"responseBuilder.AddErrorResponse<{customErrorResponseModel}>(HttpStatusCode.{responseModel.StatusCode.ToNormalizedString()});");
}

break;
case HttpStatusCode.Continue:
case HttpStatusCode.SwitchingProtocols:
Expand Down Expand Up @@ -176,11 +187,19 @@ public string Generate()
case HttpStatusCode.LoopDetected:
case HttpStatusCode.NotExtended:
case HttpStatusCode.NetworkAuthenticationRequired:
sb.AppendLine(
8,
useProblemDetailsAsDefaultResponseBody
? $"responseBuilder.AddErrorResponse<ProblemDetails>(HttpStatusCode.{responseModel.StatusCode});"
: $"responseBuilder.AddErrorResponse<string>(HttpStatusCode.{responseModel.StatusCode});");
if (string.IsNullOrEmpty(customErrorResponseModel))
{
sb.AppendLine(
8,
useProblemDetailsAsDefaultResponseBody
? $"responseBuilder.AddErrorResponse<ProblemDetails>(HttpStatusCode.{responseModel.StatusCode});"
: $"responseBuilder.AddErrorResponse<string>(HttpStatusCode.{responseModel.StatusCode});");
}
else
{
sb.AppendLine(8, $"responseBuilder.AddErrorResponse<{customErrorResponseModel}>(HttpStatusCode.{responseModel.StatusCode});");
}

break;
default:
sb.AppendLine(4, $"// TODO: Not Implemented for {responseModel.StatusCode}.");
Expand Down
Loading

0 comments on commit fcd7780

Please sign in to comment.