Skip to content

Commit 7ab01a9

Browse files
committed
Propagate ServiceResult metadata as HTTP response headers
Metadata set via WithMetadata() is now written as HTTP headers through ApiResponseBuilder.ApplyHeaders(). Same pattern as the earlier Errors propagation fix.
1 parent 15fc205 commit 7ab01a9

2 files changed

Lines changed: 33 additions & 7 deletions

File tree

src/Initium/Infrastructure/Filters/ApiResponseFilter.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,25 @@ public override void OnActionExecuted(ActionExecutedContext context)
4545
if (serviceResult.Errors != null)
4646
apiResponseBuilder.WithErrors(serviceResult.Errors.ToArray());
4747

48+
// Propagate metadata from the ServiceResult as HTTP response headers.
49+
if (serviceResult.Metadata.Count > 0)
50+
apiResponseBuilder.WithCustomHeaders(serviceResult.Metadata);
51+
52+
// Build the final response with status code and message.
53+
apiResponseBuilder
54+
.WithStatusCode(statusCode)
55+
.WithMessage(message);
56+
57+
// Write custom headers (from metadata and attributes) to the HTTP response.
58+
apiResponseBuilder.ApplyHeaders(context.HttpContext);
59+
4860
// Determine the appropriate response based on the status code:
4961
// - For 204 (No Content) and 304 (Not Modified), set a StatusCodeResult without a response body.
5062
// - For other status codes, construct a standardized ApiResponse object including HTTP context details.
5163
context.Result = statusCode switch
5264
{
5365
HttpStatusCode.NoContent or HttpStatusCode.NotModified => new StatusCodeResult((int)statusCode),
54-
_ => apiResponseBuilder
55-
.WithStatusCode(statusCode)
56-
.WithMessage(message)
57-
.BuildAsJsonResult()
66+
_ => apiResponseBuilder.BuildAsJsonResult()
5867
};
5968
}
6069
}

src/Initium/Response/ApiResponseBuilder.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,25 @@ public ApiResponseBuilder WithCustomHeaders(Dictionary<string, string> headers)
125125
/// Builds and returns the constructed <see cref="Response.ApiResponse"/> as a <see cref="JsonResult"/>.
126126
/// </summary>
127127
/// <returns>A <see cref="JsonResult"/> containing the constructed <see cref="Response.ApiResponse"/>.</returns>
128-
public JsonResult BuildAsJsonResult() => new(ApiResponse)
128+
public JsonResult BuildAsJsonResult()
129129
{
130-
StatusCode = ApiResponse.StatusCode
131-
};
130+
var result = new JsonResult(ApiResponse)
131+
{
132+
StatusCode = ApiResponse.StatusCode
133+
};
134+
135+
return result;
136+
}
137+
138+
/// <summary>
139+
/// Writes any custom headers from the <see cref="ApiResponse"/> into the HTTP response.
140+
/// Should be called before the result is executed.
141+
/// </summary>
142+
public void ApplyHeaders(Microsoft.AspNetCore.Http.HttpContext context)
143+
{
144+
if (ApiResponse.CustomHeaders == null) return;
145+
146+
foreach (var header in ApiResponse.CustomHeaders)
147+
context.Response.Headers[header.Key] = header.Value;
148+
}
132149
}

0 commit comments

Comments
 (0)