< Summary - ZhEaIsNsAaBn.Libraries coverage (affected: 23 packages)

Information
Class: ZhEaIsNsAaBn.Utilities.APIResponses.BaseResponse
Assembly: ZhEaIsNsAaBn.Utilities.APIResponses
File(s): /home/runner/work/ZhEaIsNsAaBn.Libraries.V1/ZhEaIsNsAaBn.Libraries.V1/src/UtilitiesPackages/ZhEaIsNsAaBn.Utilities.APIResponses/BaseResponse.cs
Line coverage
87%
Covered lines: 21
Uncovered lines: 3
Coverable lines: 24
Total lines: 122
Line coverage: 87.5%
Branch coverage
78%
Covered branches: 22
Total branches: 28
Branch coverage: 78.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()50%22100%
BadRequest(...)100%11100%
FromValidation(...)75%44100%
FromValidation(...)0%620%
Ok()100%11100%
op_Explicit(...)100%22100%
op_Explicit(...)100%1010100%
op_Implicit(...)100%11100%
op_Implicit(...)100%11100%
ToAPI(...)75%88100%
FromErrors(...)100%11100%
HttpStatusError(...)100%11100%

File(s)

/home/runner/work/ZhEaIsNsAaBn.Libraries.V1/ZhEaIsNsAaBn.Libraries.V1/src/UtilitiesPackages/ZhEaIsNsAaBn.Utilities.APIResponses/BaseResponse.cs

#LineLine coverage
 1namespace ZhEaIsNsAaBn.Utilities.APIResponses;
 2
 3/// <summary>
 4/// The JSON envelope every API endpoint returns: HTTP <see cref="Status"/>, <see cref="Errors"/>, a <see cref="Message"
 5/// <see cref="TraceId"/> / <see cref="TransId"/> that tie the response to the logs.
 6/// </summary>
 7public class BaseResponse
 8{
 9    /// <summary>The HTTP status code, also used as the response status by <see cref="ToAPI"/>.</summary>
 10    public int Status { get; set; }
 11
 12    /// <summary>The errors; <see langword="null"/> on success.</summary>
 13    public List<Error>? Errors { get; set; }
 14
 15    /// <summary>An optional message for the caller.</summary>
 16    public string? Message { get; set; }
 17
 18    /// <summary>The transaction id from <c>HttpContext.Items["transId"]</c>, set by <see cref="ToAPI"/>.</summary>
 19    public string? TransId { get; set; }
 20
 21    /// <summary>The trace id of the current <see cref="Activity"/>, else the request's <see cref="HttpContext.TraceIden
 36222    public string? TraceId { get; set; } = Activity.Current?.TraceId.ToString();
 23
 24
 25    /// <summary>A 400 response with <paramref name="errors"/>.</summary>
 26    /// <param name="errors">The errors.</param>
 27    /// <returns>The response.</returns>
 928    public static BaseResponse BadRequest( List<Error> errors ) => new() { Status = (int) HttpStatusCode.BadRequest, Err
 29
 30    /// <summary>A 400 response carrying the validation <paramref name="errors"/>, or 200 when there are none.</summary>
 31    /// <param name="errors">The column errors.</param>
 32    /// <returns>The response.</returns>
 33    public static BaseResponse<ValidationResponse> FromValidation( List<ColumnValidationError>? errors )
 934        => errors is { Count: > 0 }
 935               ? new BaseResponse<ValidationResponse> { Status = (int) HttpStatusCode.BadRequest, Data = errors }
 936               : new BaseResponse<ValidationResponse> { Status = (int) HttpStatusCode.OK };
 37
 38    /// <summary>A 400 response carrying the validation <paramref name="error"/>, or 200 when it is <see langword="null"
 39    /// <param name="error">The column error.</param>
 40    /// <returns>The response.</returns>
 41    public static BaseResponse<ValidationResponse> FromValidation( ColumnValidationError? error )
 042        => error is not null
 043               ? new BaseResponse<ValidationResponse> { Status = (int) HttpStatusCode.BadRequest, Data = error }
 044               : new BaseResponse<ValidationResponse> { Status = (int) HttpStatusCode.OK };
 45
 46    /// <summary>A 200 response.</summary>
 47    /// <returns>The response.</returns>
 348    public static BaseResponse Ok() => new() { Status = (int) HttpStatusCode.OK };
 49
 50    /// <summary>
 51    /// 200 on success; otherwise the errors with the status mapped from the first error (see <see cref="APIResponsesSet
 52    /// defaults here, the app's settings when <see cref="ToAPI"/> executes).
 53    /// </summary>
 54    /// <param name="response">The layer result.</param>
 55    /// <exception cref="ArgumentNullException"><paramref name="response"/> is <see langword="null"/>.</exception>
 56    public static explicit operator BaseResponse( LayerResponse response )
 57    {
 11758        ArgumentNullException.ThrowIfNull( response );
 59
 11760        return response.IsSuccess ? new BaseResponse { Status = (int) HttpStatusCode.OK } : FromErrors<BaseResponse>( re
 61    }
 62
 63    /// <summary>
 64    /// Success for a 2xx <see cref="Status"/>; otherwise a failure with the <see cref="Errors"/>, or, when there are no
 65    /// <c>HttpStatusError</c> error whose additional data holds the <c>Status</c>.
 66    /// </summary>
 67    /// <param name="response">The API response.</param>
 68    /// <exception cref="ArgumentNullException"><paramref name="response"/> is <see langword="null"/>.</exception>
 69    public static explicit operator LayerResponse( BaseResponse response )
 70    {
 1571        ArgumentNullException.ThrowIfNull( response );
 72
 1873        if ( response.Status is >= 200 and < 300 ) { return LayerResponse.Success(); }
 74
 75
 1276        var errors = response.Errors?.Where( e => e != Error.None ).ToList() ?? [];
 77
 78
 1279        return LayerResponse.Failure( errors.Count > 0 ? errors : [ HttpStatusError( response.Status ) ] );
 80    }
 81
 82    /// <summary>A failed response with one error; status mapped from it (see <see cref="APIResponsesSettings"/>).</summ
 83    /// <param name="error">The error.</param>
 4884    public static implicit operator BaseResponse( Error error ) => FromErrors<BaseResponse>( [ error ] );
 85
 86    /// <summary>A failed response with the errors; status mapped from the first one (see <see cref="APIResponsesSetting
 87    /// <param name="errors">The errors.</param>
 8588    public static implicit operator BaseResponse( List<Error> errors ) => FromErrors<BaseResponse>( errors );
 89
 90    /// <summary>
 91    /// Wraps the response in a <see cref="BaseResponseResult"/> with <see cref="Status"/> as the HTTP status code. A st
 92    /// from errors is mapped again with the app's <see cref="APIResponsesSettings"/> when the result executes.
 93    /// </summary>
 94    /// <param name="httpContext">The request; when given, fills <see cref="TraceId"/> (if empty) and <see cref="TransId
 95    /// <returns>The action result.</returns>
 96    public ObjectResult ToAPI( HttpContext? httpContext )
 97    {
 6998        if ( httpContext is not null )
 99        {
 69100            TraceId ??= httpContext.TraceIdentifier;
 69101            TransId =   httpContext.Items[ "transId" ]?.ToString() ?? string.Empty;
 102        }
 103
 104
 69105        return new BaseResponseResult( this );
 106    }
 107
 108
 109    /// <summary><see langword="true"/> when <see cref="Status"/> was mapped from <see cref="Errors"/> (not set explicit
 110    internal bool StatusFromErrors { get; private protected set; }
 111
 112
 113    /// <summary>A failed response whose status comes from the default mapping of <paramref name="errors"/>.</summary>
 114    private protected static TResponse FromErrors< TResponse >( List<Error> errors )
 115        where TResponse : BaseResponse, new()
 295116        => new() { Status = (int) new APIResponsesSettings().StatusFor( errors ), Errors = errors, StatusFromErrors = tr
 117
 118
 119    private static Error HttpStatusError( int status )
 9120        => new( "HttpStatusError", "ApiError", $"فشل الطلب (رمز الحالة {status}).", $"The request failed with HTTP statu
 9121                new Dictionary<string, object> { [ "Status" ] = status } );
 122}