12

I'm writing a RESTful API in Web API and I'm not sure how to handle errors effectively. I want the API to return JSON, and it needs to consist of the exact same format every single time - even on errors. Here are a couple of examples of what a successful and a failed response might look like.

Success:

{
    Status: 0,
    Message: "Success",
    Data: {...}
}

Error:

{
    Status: 1,
    Message: "An error occurred!",
    Data: null
}

If there is an exception - any exception at all, I want to return a response that is formed like the second one. What is the foolproof way to do this, so that no exceptions are left unhandled?

Nick Coad
  • 3,623
  • 4
  • 30
  • 63

1 Answers1

12

Implement IExceptionHandler.

Something like:

 public class APIErrorHandler : IExceptionHandler
 {
     public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
     {
         var customObject = new CustomObject
             {
                 Message = new { Message = context.Exception.Message }, 
                 Status = ... // whatever,
                 Data = ... // whatever
             };

        //Necessary to return Json
        var jsonType = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
        json.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;    

        var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, customObject, jsonType);

        context.Result = new ResponseMessageResult(response);

        return Task.FromResult(0);
    }
}

and in the configuration section of WebAPI (public static void Register(HttpConfiguration config)) write:

config.Services.Replace(typeof(IExceptionHandler), new APIErrorHandler());
Ofer Zelig
  • 17,068
  • 9
  • 59
  • 93
  • This approach seems to leave `Content-Type` set to `text/plain`, rather than `application/json` – RickNZ Jan 12 '15 at 21:40
  • No it's not. Just checked it in my own code and it keeps returning `application/json`. – Ofer Zelig Jan 22 '15 at 02:59
  • 1
    Is there any way to do this that uses content negotiation? – NathanAldenSr Feb 06 '15 at 00:18
  • I had to add System.Runtime.Serialization attributes to my custom error response object to get XML. Without the attributes web api fell back to json. – Dav Evans Oct 29 '15 at 01:10
  • @Fernando JS what did your change do? I didn't see any comments on the change (i.e. why is it different / what advantages does it have) – Ofer Zelig Dec 15 '15 at 00:51
  • 1
    @Ofer Zelig These changes pass JsonType in CreateResponse, then return "Content-Type application/json" rather than "Content-Type text/plain". I tested in default Web API 2 configs. – Fernando JS Dec 15 '15 at 23:44
  • This is nice. Just a thought though: in a public API, would you really want to expose event the exception message? Also, most complete implementations would also need a class implementing an IExceptionLogger to log the exception to a diagnostic trace – Sudhanshu Mishra May 27 '16 at 04:47
  • @dotnetguy : 1) That's an implementation detail; in code you can opt for returning a generic message to end users vs. detailed error to admins. 2) That's outside of the question at hand's scope. – Ofer Zelig May 28 '16 at 08:14
  • It's nice to still call these things out clearly, I'm sure you'd agree that a lot of newbies look at the accepted answers only and must be made aware of caveats on stuff that needs to be done before rolling out code in production – Sudhanshu Mishra May 29 '16 at 00:45
  • @dotnetguy without checking I guess there are 100s of threads about this in Meta. My view is to answer a question and potentially supply caveats if such are directly inherited from the question or answer. I don't think SO should supply newbie-proof copy & paste answers. A) because People should learn; B) because you end up contaminating answers with collateral data that doesn't help those who need focussed answers to focussed questions. But that's just my view... – Ofer Zelig May 30 '16 at 02:02
  • @NathanAldenSr If you want something that works with content negotiation, take a look here: http://stackoverflow.com/questions/39892341/how-do-i-use-a-custom-formatter-for-json-serialization/39892671?noredirect=1#comment67082581_39892671. That deals with the normal format, but when returning HtpResponseMessage it will use the right message formatter (when registered). – oligofren Oct 06 '16 at 16:14