Skip to content

Commit

Permalink
Merge pull request #58 from marcominerva/develop
Browse files Browse the repository at this point in the history
Refactor HTTP status code handling
  • Loading branch information
marcominerva committed Jun 17, 2024
2 parents 53c3061 + 9355e7f commit d220b2d
Show file tree
Hide file tree
Showing 12 changed files with 40 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ _Note: This is the library to use if you're working with Minimal APIs._

This library provides HttpContext extension methods to automatically map Operation Results (that may come, for example, from a business layer) to HTTP responses, along with the appropriate status codes.

A full example is available in the [Samples](https://github.com/marcominerva/OperationResults/tree/master/samples) folder. Search for the [registration](https://github.com/marcominerva/OperationResults/blob/master/samples/MinimalApis/OperationResults.Sample/Program.cs#L23-L25) and the [usage](https://github.com/marcominerva/OperationResults/blob/master/samples/MinimalApis/OperationResults.Sample/Program.cs#L51-L106) in [Program.cs](https://github.com/marcominerva/OperationResults/blob/master/samples/MinimalApis/OperationResults.Sample/Program.cs) file.
A full example is available in the [Samples](https://github.com/marcominerva/OperationResults/tree/master/samples) folder. Search for the [registration](https://github.com/marcominerva/OperationResults/blob/master/samples/MinimalApis/OperationResults.Sample/Program.cs#L23-L35) and the [usage](https://github.com/marcominerva/OperationResults/blob/master/samples/MinimalApis/OperationResults.Sample/Program.cs#L51-L106) in [Program.cs](https://github.com/marcominerva/OperationResults/blob/master/samples/MinimalApis/OperationResults.Sample/Program.cs) file.

**Installation**

Expand Down
4 changes: 2 additions & 2 deletions samples/Controllers/OperationResults.Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
// for the Operation Results of our Business Logic methods.
options.StatusCodesMapping.Add(CustomFailureReasons.NotAvailable, StatusCodes.Status501NotImplemented);
// If you just want to directly use HTTP status codes as failure reasons, set the following property to true.
// If you just want to directly use HTTP status codes as failure reasons, set the following property to false.
// In this way, the code you use with Result.Fail() will be used as response status code with no further mapping.
// options.UseHttpStatusCodes = true;
// options.MapStatusCodes = false;
},
//updateModelStateResponseFactory: true);
// Passing a validation error default message or a validation error message provider automatically update the ModelStateResponseFactory.
Expand Down
4 changes: 2 additions & 2 deletions samples/MinimalApis/OperationResults.Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
// for the Operation Results of our Business Logic methods.
options.StatusCodesMapping.Add(CustomFailureReasons.NotAvailable, StatusCodes.Status501NotImplemented);
// If you just want to directly use HTTP status codes as failure reasons, set the following property to true.
// If you just want to directly use HTTP status codes as failure reasons, set the following property to false.
// In this way, the code you use with Result.Fail() will be used as response status code with no further mapping.
//options.UseHttpStatusCodes = true;
options.MapStatusCodes = false;
});

builder.Services.AddEndpointsApiExplorer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public static class CustomFailureReasons
{
public const int NotAvailable = 1001;
public const int NotAvailable = FailureReasons.GenericError + 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public static IResult ToResponse<T>(this Result<T> result, HttpContext httpConte
private static IResult Problem(HttpContext httpContext, int failureReason, object? content = null, string? title = null, string? detail = null, IEnumerable<ValidationError>? validationErrors = null)
{
var options = httpContext.RequestServices.GetService<OperationResultOptions>() ?? new OperationResultOptions();
var statusCode = options.UseHttpStatusCodes ? failureReason : options.GetStatusCode(failureReason);
var statusCode = options.MapStatusCodes ? options.GetStatusCode(failureReason) : failureReason;

if (content is not null)
{
Expand Down
23 changes: 14 additions & 9 deletions src/OperationResults.AspNetCore.Http/OperationResultOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@ namespace OperationResults.AspNetCore.Http;

public class OperationResultOptions
{
public ErrorResponseFormat ErrorResponseFormat { get; set; }
public ErrorResponseFormat ErrorResponseFormat { get; set; } = ErrorResponseFormat.Default;

public Dictionary<int, int> StatusCodesMapping { get; }

public bool UseHttpStatusCodes { get; set; }
public bool MapStatusCodes { get; set; } = true;

public UnmappedFailureReasonBehavior UnmappedFailureReasonBehavior { get; set; }
public UnmappedFailureReasonBehavior UnmappedFailureReasonBehavior { get; set; } = UnmappedFailureReasonBehavior.UseDefaultStatusCode;

public int UnmappedFailureReasonStatusCode { get; set; } = StatusCodes.Status500InternalServerError;
public int UnmappedFailureReasonStatusCode { get; set; } = StatusCodes.Status501NotImplemented;

public OperationResultOptions()
{
StatusCodesMapping = new Dictionary<int, int>
{
[FailureReasons.None] = StatusCodes.Status200OK,
[FailureReasons.ItemNotFound] = StatusCodes.Status404NotFound,
[FailureReasons.Forbidden] = StatusCodes.Status403Forbidden,
[FailureReasons.DatabaseError] = StatusCodes.Status500InternalServerError,
[FailureReasons.ClientError] = StatusCodes.Status400BadRequest,
[FailureReasons.InvalidFile] = StatusCodes.Status415UnsupportedMediaType,
[FailureReasons.Conflict] = StatusCodes.Status409Conflict,
[FailureReasons.Unauthorized] = StatusCodes.Status401Unauthorized,
[FailureReasons.Forbidden] = StatusCodes.Status403Forbidden,
[FailureReasons.ItemNotFound] = StatusCodes.Status404NotFound,
[FailureReasons.InvalidRequest] = StatusCodes.Status406NotAcceptable,
[FailureReasons.Timeout] = StatusCodes.Status408RequestTimeout,
[FailureReasons.Conflict] = StatusCodes.Status409Conflict,
[FailureReasons.InvalidFile] = StatusCodes.Status415UnsupportedMediaType,
[FailureReasons.InvalidContent] = StatusCodes.Status422UnprocessableEntity,
[FailureReasons.DatabaseError] = StatusCodes.Status500InternalServerError,
[FailureReasons.NetworkError] = StatusCodes.Status500InternalServerError,
[FailureReasons.ServiceUnavailable] = StatusCodes.Status503ServiceUnavailable,
[FailureReasons.GenericError] = StatusCodes.Status500InternalServerError
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="OperationResultTools" Version="1.0.25" />
<PackageReference Include="OperationResultTools" Version="1.0.26" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public enum UnmappedFailureReasonBehavior
{
UseFailureReason,
UseDefaultStatusCode,
UseFailureReason
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public static IActionResult ToResponse<T>(this Result<T> result, HttpContext htt
private static IActionResult Problem(HttpContext httpContext, int failureReason, object? content = null, string? title = null, string? detail = null, IEnumerable<ValidationError>? validationErrors = null)
{
var options = httpContext.RequestServices.GetService<OperationResultOptions>() ?? new OperationResultOptions();
var statusCode = options.UseHttpStatusCodes ? failureReason : options.GetStatusCode(failureReason);
var statusCode = options.MapStatusCodes ? options.GetStatusCode(failureReason) : failureReason;

if (content is not null)
{
Expand Down
23 changes: 14 additions & 9 deletions src/OperationResults.AspNetCore/OperationResultOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@ namespace OperationResults.AspNetCore;

public class OperationResultOptions
{
public ErrorResponseFormat ErrorResponseFormat { get; set; }
public ErrorResponseFormat ErrorResponseFormat { get; set; } = ErrorResponseFormat.Default;

public Dictionary<int, int> StatusCodesMapping { get; }

public bool UseHttpStatusCodes { get; set; }
public bool MapStatusCodes { get; set; } = true;

public UnmappedFailureReasonBehavior UnmappedFailureReasonBehavior { get; set; }
public UnmappedFailureReasonBehavior UnmappedFailureReasonBehavior { get; set; } = UnmappedFailureReasonBehavior.UseDefaultStatusCode;

public int UnmappedFailureReasonStatusCode { get; set; } = StatusCodes.Status500InternalServerError;
public int UnmappedFailureReasonStatusCode { get; set; } = StatusCodes.Status501NotImplemented;

public OperationResultOptions()
{
StatusCodesMapping = new Dictionary<int, int>
{
[FailureReasons.None] = StatusCodes.Status200OK,
[FailureReasons.ItemNotFound] = StatusCodes.Status404NotFound,
[FailureReasons.Forbidden] = StatusCodes.Status403Forbidden,
[FailureReasons.DatabaseError] = StatusCodes.Status500InternalServerError,
[FailureReasons.ClientError] = StatusCodes.Status400BadRequest,
[FailureReasons.InvalidFile] = StatusCodes.Status415UnsupportedMediaType,
[FailureReasons.Conflict] = StatusCodes.Status409Conflict,
[FailureReasons.Unauthorized] = StatusCodes.Status401Unauthorized,
[FailureReasons.Forbidden] = StatusCodes.Status403Forbidden,
[FailureReasons.ItemNotFound] = StatusCodes.Status404NotFound,
[FailureReasons.InvalidRequest] = StatusCodes.Status406NotAcceptable,
[FailureReasons.Timeout] = StatusCodes.Status408RequestTimeout,
[FailureReasons.Conflict] = StatusCodes.Status409Conflict,
[FailureReasons.InvalidFile] = StatusCodes.Status415UnsupportedMediaType,
[FailureReasons.InvalidContent] = StatusCodes.Status422UnprocessableEntity,
[FailureReasons.DatabaseError] = StatusCodes.Status500InternalServerError,
[FailureReasons.NetworkError] = StatusCodes.Status500InternalServerError,
[FailureReasons.ServiceUnavailable] = StatusCodes.Status503ServiceUnavailable,
[FailureReasons.GenericError] = StatusCodes.Status500InternalServerError
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="OperationResultTools" Version="1.0.25" />
<PackageReference Include="OperationResultTools" Version="1.0.26" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public enum UnmappedFailureReasonBehavior
{
UseFailureReason,
UseDefaultStatusCode,
UseFailureReason
}

0 comments on commit d220b2d

Please sign in to comment.