Skip to content

Commit 36f7108

Browse files
committed
Improve filters by uniformizing results
1 parent ca46835 commit 36f7108

File tree

3 files changed

+36
-42
lines changed

3 files changed

+36
-42
lines changed
Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Net;
22
using Microsoft.AspNetCore.Mvc.Filters;
33
using Initium.Exceptions;
4+
using Initium.Helpers;
45
using Initium.Response;
56

67
namespace Initium.Filters;
@@ -20,39 +21,29 @@ public void OnException(ExceptionContext context)
2021
{
2122
// Start building the ApiResponse using the Fluent Builder
2223
var apiResponseBuilder = ApiResponseBuilder.CreateFromContext(context.HttpContext);
23-
24-
// Use pattern switch to handle exceptions
25-
context.Result = context.Exception switch
24+
25+
// Determine the HTTP status code:
26+
var statusCode = context.Exception switch
2627
{
27-
ApiException ex => apiResponseBuilder
28-
.WithMessage(ex.Message)
29-
.WithStatusCode(ex.StatusCode)
30-
.BuildAsJsonResult(),
31-
32-
NotImplementedException ex => apiResponseBuilder
33-
.WithMessage(ex.Message)
34-
.WithStatusCode(HttpStatusCode.NotImplemented)
35-
.BuildAsJsonResult(),
36-
37-
_ => apiResponseBuilder
38-
.WithMessage("An unexpected error occurred.")
39-
.WithStatusCode(HttpStatusCode.InternalServerError)
40-
.BuildAsJsonResult()
28+
ApiException exception => exception.StatusCode,
29+
NotImplementedException => HttpStatusCode.NotImplemented,
30+
_ => HttpStatusCode.InternalServerError
4131
};
4232

33+
// Determine the response message:
34+
// 1. Use the exception's message if it's not null or whitespace.
35+
// 2. Otherwise, get the message from [ApiResponse] attributes.
36+
// 3. If none is found, use the default message for the StatusCode.
37+
var message =
38+
(string.IsNullOrWhiteSpace(context.Exception.Message) ? null : context.Exception.Message)
39+
?? ApiResponseHelper.GetApiResponseMessage(context.ActionDescriptor, statusCode)
40+
?? ApiResponseHelper.GetDefaultMessageForStatusCode(statusCode);
41+
42+
// Construct a standardized ApiResponse object including HTTP context details.
4343
context.ExceptionHandled = true;
44+
context.Result = apiResponseBuilder
45+
.WithStatusCode(statusCode)
46+
.WithMessage(message)
47+
.BuildAsJsonResult();
4448
}
45-
}
46-
//
47-
// public static implicit operator ActionResult(ServiceResult result)
48-
// {
49-
// if (result.Success && result.StatusCode == HttpStatusCode.NoContent)
50-
// {
51-
// return new NoContentResult();
52-
// }
53-
//
54-
// return new ObjectResult(result)
55-
// {
56-
// StatusCode = (int)result.StatusCode
57-
// };
58-
// }
49+
}

src/Initium/Filters/ApiResponseFilter.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ public override void OnActionExecuted(ActionExecutedContext context)
2222
// Check if the result of the action is an ObjectResult containing a ServiceResult.
2323
if (context.Result is not ObjectResult { Value: ServiceResult serviceResult }) return;
2424

25+
// Start building the ApiResponse using the Fluent Builder
26+
var apiResponseBuilder = ApiResponseBuilder.CreateFromContext(context.HttpContext);
27+
2528
// Determine the HTTP status code:
2629
// 1. Use ServiceResult status code if set.
2730
// 2. Otherwise, use the default based on the HTTP method.
@@ -32,26 +35,22 @@ public override void OnActionExecuted(ActionExecutedContext context)
3235
// Determine the response message:
3336
// 1. Use ServiceResult message if set.
3437
// 2. Otherwise, get the message from [ApiResponse] attributes.
35-
// 3. If none found, use the default message for the StatusCode.
38+
// 3. If none is found, use the default message for the StatusCode.
3639
var message =
37-
serviceResult.Message
38-
?? GetApiResponseMessage(context, statusCode)
40+
serviceResult.Message
41+
?? ApiResponseHelper.GetApiResponseMessage(context.ActionDescriptor, statusCode)
3942
?? ApiResponseHelper.GetDefaultMessageForStatusCode(statusCode);
4043

4144
// Determine the appropriate response based on the status code:
4245
// - For 204 (No Content) and 304 (Not Modified), set a StatusCodeResult without a response body.
43-
// - For other status codes, create a standardized ApiResponse object including HTTP context details.
46+
// - For other status codes, construct a standardized ApiResponse object including HTTP context details.
4447
context.Result = statusCode switch
4548
{
4649
HttpStatusCode.NoContent or HttpStatusCode.NotModified => new StatusCodeResult((int)statusCode),
47-
_ => ApiResponseBuilder
48-
.CreateFromContext(context.HttpContext)
50+
_ => apiResponseBuilder
4951
.WithStatusCode(statusCode)
5052
.WithMessage(message)
5153
.BuildAsJsonResult()
5254
};
5355
}
54-
55-
private static string? GetApiResponseMessage(ActionExecutedContext context, HttpStatusCode statusCode) =>
56-
ApiResponseHelper.GetApiResponseAttributes(context.ActionDescriptor).FirstOrDefault(attribute => attribute.StatusCode == statusCode)?.Message;
5756
}

src/Initium/Helpers/ApiResponseHelper.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ public static IEnumerable<ApiResponseAttribute> GetApiResponseAttributes(ActionD
6060
public static HttpStatusCode GetDefaultStatusCode(HttpContext context) => context.Request.Method.ToUpper() switch
6161
{
6262
"POST" => HttpStatusCode.Created,
63-
"DELETE" => HttpStatusCode.NoContent,
64-
_ => (HttpStatusCode)context.Response.StatusCode
63+
"DELETE" or "PATCH" or "PUT" => HttpStatusCode.NoContent,
64+
"GET" or "HEAD" => HttpStatusCode.OK,
65+
_ => context.Response.StatusCode > 0 ? (HttpStatusCode)context.Response.StatusCode : HttpStatusCode.InternalServerError
6566
};
67+
68+
public static string? GetApiResponseMessage(ActionDescriptor actionDescriptor, HttpStatusCode statusCode) =>
69+
GetApiResponseAttributes(actionDescriptor).FirstOrDefault(attribute => attribute.StatusCode == statusCode)?.Message;
6670
}

0 commit comments

Comments
 (0)