| | | 1 | | using ArturRios.Output; |
| | | 2 | | using ArturRios.Util.Http; |
| | | 3 | | using Microsoft.AspNetCore.Mvc; |
| | | 4 | | |
| | | 5 | | namespace ArturRios.Util.WebApi.AspNetCore; |
| | | 6 | | |
| | | 7 | | /// <summary>Converts output envelopes from <c>ArturRios.Output</c> into ASP.NET Core <see cref="ActionResult{TValue}"/> |
| | | 8 | | /// instances. The HTTP status is resolved in order: an explicit <c>statusCode</c>, then a lookup of the envelope's |
| | | 9 | | /// first error (on failure) or first message (on success) in an optional <c>statusMap</c>, then a default of 200 on |
| | | 10 | | /// success and 400 on failure.</summary> |
| | | 11 | | public static class ResponseResolver |
| | | 12 | | { |
| | | 13 | | /// <summary>Wraps a <see cref="PaginatedOutput{T}"/> in an <see cref="ActionResult{TValue}"/>. The HTTP status is |
| | | 14 | | /// resolved from <paramref name="statusCode"/>, then <paramref name="statusMap"/>, then the 200/400 default.</summa |
| | | 15 | | /// <param name="paginatedOutput">The paginated result envelope to return.</param> |
| | | 16 | | /// <param name="statusCode">Optional explicit HTTP status code; when supplied it wins over the map and default.</pa |
| | | 17 | | /// <param name="statusMap">Optional map from the first error (on failure) or first message (on success) to an HTTP |
| | | 18 | | /// status code. The caller owns the dictionary and its key comparer.</param> |
| | | 19 | | public static ActionResult<PaginatedOutput<T>> Resolve<T>(PaginatedOutput<T> paginatedOutput, |
| | | 20 | | int? statusCode = null, IReadOnlyDictionary<string, int>? statusMap = null) |
| | 1 | 21 | | { |
| | 1 | 22 | | var httpStatusCode = ResolveStatusCode(paginatedOutput, statusCode, statusMap); |
| | | 23 | | |
| | 1 | 24 | | return new ObjectResult(paginatedOutput) { StatusCode = httpStatusCode }; |
| | 1 | 25 | | } |
| | | 26 | | |
| | | 27 | | /// <summary>Wraps a <see cref="DataOutput{T}"/> in an <see cref="ActionResult{TValue}"/>. The HTTP status is |
| | | 28 | | /// resolved from <paramref name="statusCode"/>, then <paramref name="statusMap"/>, then the 200/400 default.</summa |
| | | 29 | | /// <param name="dataOutput">The result envelope to return.</param> |
| | | 30 | | /// <param name="statusCode">Optional explicit HTTP status code; when supplied it wins over the map and default.</pa |
| | | 31 | | /// <param name="statusMap">Optional map from the first error (on failure) or first message (on success) to an HTTP |
| | | 32 | | /// status code. The caller owns the dictionary and its key comparer.</param> |
| | | 33 | | public static ActionResult<DataOutput<T?>> Resolve<T>(DataOutput<T?> dataOutput, int? statusCode = null, |
| | | 34 | | IReadOnlyDictionary<string, int>? statusMap = null) |
| | 1 | 35 | | { |
| | 1 | 36 | | var httpStatusCode = ResolveStatusCode(dataOutput, statusCode, statusMap); |
| | | 37 | | |
| | 1 | 38 | | return new ObjectResult(dataOutput) { StatusCode = httpStatusCode }; |
| | 1 | 39 | | } |
| | | 40 | | |
| | | 41 | | /// <summary>Wraps a <see cref="ProcessOutput"/> in an <see cref="ActionResult{TValue}"/>. The HTTP status is |
| | | 42 | | /// resolved from <paramref name="statusCode"/>, then <paramref name="statusMap"/>, then the 200/400 default.</summa |
| | | 43 | | /// <param name="processOutput">The result envelope to return.</param> |
| | | 44 | | /// <param name="statusCode">Optional explicit HTTP status code; when supplied it wins over the map and default.</pa |
| | | 45 | | /// <param name="statusMap">Optional map from the first error (on failure) or first message (on success) to an HTTP |
| | | 46 | | /// status code. The caller owns the dictionary and its key comparer.</param> |
| | | 47 | | public static ActionResult<ProcessOutput> Resolve(ProcessOutput processOutput, int? statusCode = null, |
| | | 48 | | IReadOnlyDictionary<string, int>? statusMap = null) |
| | 8 | 49 | | { |
| | 8 | 50 | | var httpStatusCode = ResolveStatusCode(processOutput, statusCode, statusMap); |
| | | 51 | | |
| | 8 | 52 | | return new ObjectResult(processOutput) { StatusCode = httpStatusCode }; |
| | 8 | 53 | | } |
| | | 54 | | |
| | | 55 | | private static int ResolveStatusCode(ProcessOutput output, int? statusCode, |
| | | 56 | | IReadOnlyDictionary<string, int>? statusMap) |
| | 10 | 57 | | { |
| | 10 | 58 | | if (statusCode.HasValue) |
| | 1 | 59 | | { |
| | 1 | 60 | | return statusCode.Value; |
| | | 61 | | } |
| | | 62 | | |
| | 9 | 63 | | if (statusMap is not null) |
| | 7 | 64 | | { |
| | 7 | 65 | | var key = output.Success ? output.Messages.FirstOrDefault() : output.Errors.FirstOrDefault(); |
| | | 66 | | |
| | 7 | 67 | | if (key is not null && statusMap.TryGetValue(key, out var mapped)) |
| | 5 | 68 | | { |
| | 5 | 69 | | return mapped; |
| | | 70 | | } |
| | 2 | 71 | | } |
| | | 72 | | |
| | 4 | 73 | | return GetDefaultStatusCode(output.Success); |
| | 10 | 74 | | } |
| | | 75 | | |
| | 4 | 76 | | private static int GetDefaultStatusCode(bool success) => success ? HttpStatusCodes.Ok : HttpStatusCodes.BadRequest; |
| | | 77 | | } |