Web Api Failure Mode Handling

174 阅读1分钟

希望能以一种相对统一的方式来处理Web API的Response

  • StatusCode() 是ControllerBase的,所以就为之写了扩展方法
  • 设计为XXXService的所有方法,全都返回一个继承自Response的类型的实例

        [HttpGet]
        public ActionResult<XXXResponse> Method1()
        {
            try
            {
                var response = m_service.DoSomething();

                return this.UnifyResponseFormat(response);

            }
            catch (Exception e)
            {
                return this.FormatResponseForFailure((int)HttpStatusCode.InternalServerError, e.Message);
            }
        }
        
        [HttpPost]
        public IActionResult Method2([FromBody]XXXRequest request)
        {
            try
            {
                var validationResponse = m_service.ValidateRequest(request);

                if(this.IsBadRequest(validationResponse))
                {
                    return this.FormatResponseForFailure(validationResponse);
                }

                var response = m_service.DoSomething(request);

                return this.UnifyResponseFormat(response);

            }
            catch(Exception e)
            {
                return this.FormatResponseForFailure((int)HttpStatusCode.InternalServerError, e.Message);
            }
        }

    public class XXXResponse : Response
    {

        [JsonProperty(PropertyName = "A")]
        public A a { get; set; }
    }
    
    public class Response
    {
        [JsonIgnore]
        [JsonProperty(PropertyName = "status")]
        public HttpStatusCode Status { get; set; } = HttpStatusCode.OK;

        [JsonIgnore]
        [JsonProperty(PropertyName = "reason")]
        public string Reason { get; set; } = String.Empty;
    }

    public static class ResponseHelper
    {
        public static ObjectResult UnifyResponseFormat(this ControllerBase controllerBase, Response response)
        {
            int statusCode = (int)response.Status;

            switch (response.Status)
            {
                case HttpStatusCode.OK:
                    return controllerBase.FormatResponseForSuccess(response);

                case HttpStatusCode.InternalServerError:
                    return controllerBase.FormatResponseForFailure(response);
            }
            return controllerBase.FormatResponseForFailure((int)HttpStatusCode.BadRequest, "failed for certain reason. And also the response status code might not be properly handled by server");
        }

        public static ObjectResult FormatResponseForFailure(this ControllerBase controllerBase, Response response)
        {
            int statusCode = (int)response.Status;

            return controllerBase.StatusCode((int)response.Status, response.Reason);
        }

        public static ObjectResult FormatResponseForFailure(this ControllerBase controllerBase, int statusCode, string reason)
        {
            return controllerBase.StatusCode(statusCode, reason);
        }

        public static ObjectResult FormatResponseForSuccess(this ControllerBase controllerBase, Response response)
        {
            int statusCode = (int)response.Status;

            return controllerBase.StatusCode(statusCode, response);
        }

        public static bool IsBadRequest(this ControllerBase controllerBase, Response response)
        {
            return response.Status == HttpStatusCode.BadRequest;
        }
    }