GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||
GeezerVison is showing stackify.com — Web API Error Handling: How To Make Debugging Easier - Stackify
Retrace will reach End of Life on March 31, 2027. Click here to learn more.
Web API Error Handling: How To Make Debugging Easier
By: Sylvia | October 25, 2018 Whether you’re the consumer or producer of an API, you’ve no doubt seen that good error handling can make debugging easier. And you may have noticed that error handling works best when everyone speaks the same language and has the same expectations. But what makes for good error handling? And how can we implement it and ensure consistency across our application? Today, let’s look at the problem of error handling from two angles: the what and the how. And since tonight is pizza night, I’m going to go with a pizza theme for our examples later on. First, let’s consider the what. What Are Good API Errors?Easy-to-use applications take many things into account. One of those is providing helpful and descriptive errors to their consumers. And a great place to start involves looking at standards. Since much of the web uses JSON and REST, we’ll focus on using what’s outlined for the JSON API. Even more specifically, we’re going to look at typical error codes that we see in most web API’s—4xx and 5xx errors. Good API errors differentiate client and server errorsThe most basic division of errors identifies whether the problem is a result of a client or server error. 4xx-level errors are client errors. These are errors that the client can solve on their own by changing their request. And then 5xx errors are server errors, which indicate to the client that it’s probably not something they did wrong and that they should either retry or contact support. This is a basic division. Unfortunately, sometimes applications get it wrong. Whether it’s speeding through to a deadline or not having a good error handling template to follow, mistakes do happen. So what you’ll want to do (and we’ll cover this later) is make sure that your application is set up with global exception handling and filtering to provide your consumers with appropriate codes.
Good API errors use status codes appropriatelyOne of the first errors most of us encounter is the infamous HTTP 404 status code. It’s a clear indicator to the consumer that whatever they’re looking for is not there. But you may have also seen the vast list of error codes that you’re not as familiar with. How do you know which to use? And how specific do you have to get? Tip 1: Stick with well-known codesMy recommendation would be to not attempt to use all the error codes available. There are basic ones that most developers know and can recognize. And others that are more obscure and that will lead to confusion. So what error codes should we use? Well, I advise that you get familiar with at least some of them. The ones listed below are the ones I would expect to occasionally see when I call an API. Therefore I would want an application developer to generate them under the right conditions.
Now you may have noticed that I didn’t include codes like 405-Method Not Allowed or 503-Service Unavailable. These are common codes, but I would not expect an application developer to generate them. They’re either handled by frameworks, servers, or network components already. Tip 2: Avoid codes you don’t understandMany developers get a bit overzealous when they first learn about all the HTTP status codes available. They want to use the absolute most correct code for every situation. However, this results in unnecessary complexity in their application. It also causes consuming applications to modify their logic as well to account for more codes that could be returned. For example, if a request header field is too large, then yes, sure, you could send a 431-Request Header Fields Too Large as the response. But then you’re forcing the consuming application’s developer to look up 431 to find out what it means and write logic to expect that response. Instead, send a 400-Bad Request and provide a helpful description that’s easy to read and understand. Additionally, there are codes that are custom to particular uses. Let’s consider 498-Token Expired and 499-Invalid Token. When you’re first setting up your authentication, it may be tempting to use these. However, upon further inspection, you may notice that both of these are specifically for use with ArcGIS Server—whatever that may be. Additionally, 499 can also be used by nginx for indicating that a client has closed the connection. So in this case, send back a 401-Unauthorized and provide a good message that gives enough information for the client to fix the problem. Additionally, giving your consumers a 507-Insufficient Storage or 508-Loop Detected could give bad guys more information on how to bring your system down. Don’t make your consumers troubleshoot for you. Just say, Hey, sorry—Internal Server Error. Try again and if you still have problems, here’s an easy way to reach out and get help.
Tip 3: Provide the right number of errorsPer the JSON API spec, “A server MAY choose to stop processing as soon as a problem is encountered, or it MAY continue processing and encounter multiple problems.” They use the language “MAY” for a reason. It’s up to you. At this point, you should consider your customers and what makes sense for them. Does it make sense to first send a “Pizza size is required” error and then wait until the next submission to tell them that, oh, by the way, “Crust type is required,” too? In this case, the answer is obvious. But there may be times when you’ll have to consider the options. For example, if errors only occur after a number of computationally expensive steps, it might make sense to return errors one at a time. In either case, always consider the consumer and the logic that will be implemented on their side. Do they want to know sooner or later that you don’t deliver to their address? So what’s an example of errors that you would give one at a time? If you receive a request that results in a 401 because the token is not good, there’s no reason to continue on and also let them know that their request was also bad for other reasons. They’re not authorized, so they don’t need any additional information that could clue them in on your internal system structure. Tip 4: Roll up to the most relevant errorOnce again, back to the JSON API spec: “When a server encounters multiple problems for a single request, the most generally applicable HTTP error code SHOULD be used in the response. For instance, 400-Bad Request might be appropriate for multiple 4xx errors, or 500-Internal Server Error might be appropriate for multiple 5xx errors.” Pretty simple: always choose the most relevant generalized error over the more accurate (but too technical) specific error. Tip 5: Explain what went wrongThe standard goes on to tell you what MAY be included in the error message. They don’t take an opinionated stance on the result because they want it to be open for many use cases. My opinionated stance says that you should try to include the following:
Bonus points go to those of you that also add the following:
Tip 6: Separate general and domain errorsIn addition to differentiating between client and server errors, as well as the different status codes, we can also classify errors as either general or domain-specific. This helps in deciding if we should write custom handling and messaging around it, or if it’s a well-known error condition. General errorsGeneral errors include things like using the wrong HTTP verb, failing authentication, or failing authorization. It’s typically good to stop processing quickly when these happen and get a response out to consumers. General errors are typically not domain-specific. Domain errorsThese are more specific to your domain. As an example, consider if we had a DeliveryUnavailableException or an OrderAlreadyExistsException. There might be additional things you’d want to do when these types of errors are encountered. How Should We Implement Error Handling?Okay, so now we know what errors will provide solid information for our consumers. Next, how do we actually go about it? There are a few different things we can do, like creating filters and error handlers. Let’s look at each of these and see how it’s done. 1. Create filtersYou don’t want to repeat yourself. And you want to make sure that all your methods handle errors the same way. That way, there’s one less thing to worry about when you create yet another endpoint. A good option for this involves writing validation and exception filters that catch errors and treat them in a consistent manner. Validation filtersFirst, let’s look at errors related to validation. In this case, instead of checking each field in our controller or service, we can add basic validation directly to our model, as shown below. public class Pizza
{
[Require]
public string Size {get; set;}
[Require]
public string CrustType {get; set;}
public string CrustSeasoning {get; set;}
public List<Topping> Toppings {get; set;}
[DataType(DataType.Date)]
public DateTime OrderDate{get; set;}
}
And then we can validate all our models in our ValidationActionFilter. public class ValidationActionFilter: ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid) {
actionContext.Response = actionContext.Request
.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
}
}
}
Exception filtersBut what should we do with other types of exceptions? We can use a filter for those, as well. First, let’s create our exception class. public class PizzaParlorException: Exception
{
public PizzaParlorException(HttpStatusCode statusCode, string errorCode, string errorDescription): base($"{errorCode}::{errorDescription}")
{
StatusCode = statusCode;
}
public PizzaParlorException(HttpStatusCode statusCode)
{
StatusCode = statusCode;
}
public HttpStatusCode StatusCode {get;}
}
And now let’s create our filter that will process our exceptions. public class PizzaParlorExceptionFilterAttribute: ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var exception = context.Exception as PizzaParlorException;
if (exception != null) {
context.Response = context.Request.CreateErrorResponse(
exception.StatusCode, exception.Message);
}
}
}
And add it to our GlobalConfiguration. GlobalConfiguration.Configuration.Filters.Add(new PizzaParlorExceptionFilterAttribute()); Now in our controllers, we throw exceptions by extending our PizzaParlorException like this: public class OutOfDeliveryZoneException: PizzaParlorException
{
public OutOfDeliveryZoneException(): base(HttpStatusCode.BadRequest)
{
}
}
// or perhaps the following
public class PizzaDeliveryAuthorizationException: PizzaParlorException
{
public PizzaDeliveryAuthorizationException(): base(HttpStatusCode.NotAuthorized)
{
}
}
But that’s not the only way to handle exceptions. We can also use a GlobalErrorHandler. Try Stackify’s free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python. 2. Create a GlobalExceptionHandlerFirst off, why would we want to use a GlobalErrorHandler over an ExceptionFilterAttribute? Well, there are some exceptions that our filters will not catch. From the ASP.NET site, there are errors that will not be caught by our filters above. This includes exceptions thrown:
And since we want to be covered in these scenarios as well, let’s add our GlobalExceptionHandler. class GlobalPizzaParlorExceptionHandler: ExceptionHandler
{
public override void HandleCore(ExceptionHandlerContext context)
{
context.Result = new TextPlainErrorResult
{
Request = context.ExceptionContext.Request,
Content = "Pizza Down! We have an Error! Please call the parlor to complete your order."
};
}
private class TextPlainErrorResult: IHttpActionResult
{
public HttpRequestMessage Request {get; set;}
public string Content {get; set;}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response =
new HttpResponseMessage(HttpStatusCode.InternalServerError);
response.Content = new StringContent(Content);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}
Now, what do we need to do in order for that filter to catch the exception? Add it to our GlobalConfiguration. public static class SetupFiltersExtensions
{
public static IAppBuilder SetupFilters(this IAppBuilder builder, HttpConfiguration config)
{
config.Services.Replace(typeof (IExceptionHandler), new PizzaParlorExceptionHandler());
return builder;
}
}
Now there’s just one more thing we’ll want to do. 3. Create a LoggerHandlerWith the GlobalExceptionHanlder, there’s still a chance that an exception will not be caught here. However, we’re guaranteed to be able to log it. And we’re able to set up as many exception loggers as we need. I’m just going to use log4net’s logger in this example. public class Log4NetExceptionLogger: ExceptionLogger
{
private ILog log = LogManager.GetLogger(typeof(Log4NetExceptionLogger));
public async override Task LogAsync(ExceptionLoggerContext context, System.Threading.CancellationToken cancellationToken)
{
log.Error("An unhandled exception occurred.", context.Exception);
await base.LogAsync(context, cancellationToken);
}
public override void Log(ExceptionLoggerContext context)
{
log.Error("An unhandled exception occurred.", context.Exception);
base.Log(context);
}
public override bool ShouldLog(ExceptionLoggerContext context)
{
return base.ShouldLog(context);
}
}
And again, make sure to add it to your configuration. public static class WebApiConfig
{
public static IAppBuilder RegisterApiConfig(this IAppBuilder app, HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Services.Add(typeof(IExceptionLogger), new Log4NetExceptionLogger());
return app;
}
}
One additional step you should take—use the StackifyAppender. This way, Retrace is set up to automatically collect all your logging messages. Try Retrace’s free, two week trial today <log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="StackifyAppender" />
</root>
<appender name="StackifyAppender" type="StackifyLib.log4net.StackifyAppender, StackifyLib.log4net" />
</log4net>
Consider Your Errors Handled!And that’s it for today. We went over the basics of what errors provide to our consumers, as well as how to implement errors in our ASP.NET application. Now you’re ready to provide the right error and handle exceptions consistently throughout your application. As your next step, take a look at your current projects and error handling. Verify that you’re providing the right web API error in the right context, and consider ways that you can make it easier for your consumers to fix problems on their own. Related posts:Improve Your Code with Retrace APMStackify's APM tools are used by thousands of .NET, Java, PHP, Node.js, Python, & Ruby developers all over the world. Get the latest news, tips, and guides on software development.Join the community of 40,000 developers that subscribe to our newsletter. Popular Posts
indobet
toto slot
toto
toto
bobatoto daftar
logototo
patentoto
situs toto slot 4D
toto
bayitoto
popotogel prize hongkong malam ini
joker11
lingkartoto
depo 5k
slot
sbobet88
sbobet88
https://nolimithoki.dev/
dinasti33 slot
slot jepang
https://www.juara288.asia/
slot 4d
toto
toto
situs toto
flokitoto
slot gacor
logototo
slot depo 5k
bobatoto
bobatoto
bobatoto
sontogel
mpo slot
situs toto
slot
situs slot
bobatoto
kari4d
kari4d
kari4d
kari4d
pascol4d
pascol4d
pascol4d
slot gacor
bento11 link
slot gacor
toto
toto slot
toto
situs slot
situs slot
situs slot
https://www.asupan188.dev/
slot gacor gampang menang
toto
slot gacor
bwo303
situs toto
toto slot
slot gacor
slot88
slot gacor
situs slot
link slot
slot gacor
pucuk4d
PASCOL4D
situs slot
link slot
pajaktoto
slotvip
situs toto
toto slot
situs slot
situs slot
situs slot
toto
slot gacor
slot777
situs slot
link slot
situs judi bola
POPOTOGEL : Situs Resmi Bandar Toto Togel Macau dengan Prediksi Gokil Pasti Akurat
link slot
slot gacor
situs slot
slot gacor
slot gacor
situs slot
link slot
gacor
Slot88
Slot88
slot gacor
situs toto
toto
slot pulsa
slot777
link slot gacor
situs gacor
slot gacor
leon188
slot gacor
slot gacor
slot gacor
Slot88
slot gacor
situs slot
slot gacor
Slot88
slot gacor
slot terbaru
slot gacor
situs gacor
situs slot
slot gacor
situs slot
Situs Slot
POPOTOGEL: Regulasi Bandar Situs Togel Resmi & Bola Mix Parlay Asia Terpercaya
StreamEast
Jpmania
slot resmi
slot
slot resmi
slot
bayitoto
patentoto
link gacor
slot gacor
kari4d
slot gacor
AMANAHTOTO
slot gacor
slot gacor
AMANAHTOTO
pascol4d
kari4d
AMANAHTOTO
kari4d
bragatoto
dokter88
slot gacor
slot game
patentoto
pucuk4d
rokokbet
rokokbet
kari4d
pascol4d
LOGIN PASCOL4D
pucuk4d
roma77
judi bola
slot depo 10k
mpo slot
Girang4d
KARI4D
StreamEast
AMANAHTOTO
jutatoto
PARLAY
slot88
slot depo 5k
hoki99
pascol4d
pkv games
roma77
Slot
poker
slot
indobet
toto slot
toto
toto
bobatoto daftar
logototo
patentoto
situs toto slot 4D
toto
bayitoto
popotogel prize hongkong malam ini
joker11
lingkartoto
depo 5k
slot
sbobet88
sbobet88
https://nolimithoki.dev/
dinasti33 slot
slot jepang
https://www.juara288.asia/
slot 4d
toto
toto
situs toto
flokitoto
slot gacor
logototo
slot depo 5k
bobatoto
bobatoto
bobatoto
sontogel
mpo slot
situs toto
slot
situs slot
bobatoto
kari4d
kari4d
kari4d
kari4d
pascol4d
pascol4d
pascol4d
slot gacor
bento11 link
slot gacor
toto
toto slot
toto
situs slot
situs slot
situs slot
https://www.asupan188.dev/
slot gacor gampang menang
toto
slot gacor
bwo303
situs toto
toto slot
slot gacor
slot88
slot gacor
situs slot
link slot
slot gacor
pucuk4d
PASCOL4D
situs slot
link slot
pajaktoto
slotvip
situs toto
toto slot
situs slot
situs slot
situs slot
toto
slot gacor
slot777
situs slot
link slot
situs judi bola
POPOTOGEL : Situs Resmi Bandar Toto Togel Macau dengan Prediksi Gokil Pasti Akurat
link slot
slot gacor
situs slot
slot gacor
slot gacor
situs slot
link slot
gacor
Slot88
Slot88
slot gacor
situs toto
toto
slot pulsa
slot777
link slot gacor
situs gacor
slot gacor
leon188
slot gacor
slot gacor
slot gacor
Slot88
slot gacor
situs slot
slot gacor
Slot88
slot gacor
slot terbaru
slot gacor
situs gacor
situs slot
slot gacor
situs slot
Situs Slot
POPOTOGEL: Regulasi Bandar Situs Togel Resmi & Bola Mix Parlay Asia Terpercaya
StreamEast
Jpmania
slot resmi
slot
slot resmi
slot
bayitoto
patentoto
link gacor
slot gacor
kari4d
slot gacor
AMANAHTOTO
slot gacor
slot gacor
AMANAHTOTO
pascol4d
kari4d
AMANAHTOTO
kari4d
bragatoto
dokter88
slot gacor
slot game
patentoto
pucuk4d
rokokbet
rokokbet
kari4d
pascol4d
LOGIN PASCOL4D
pucuk4d
roma77
judi bola
slot depo 10k
mpo slot
Girang4d
KARI4D
StreamEast
AMANAHTOTO
jutatoto
PARLAY
slot88
slot depo 5k
hoki99
pascol4d
pkv games
roma77
Slot
poker
slot
| ||||||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |