Failing Fast in ASP.NET Core
Using Guards To Fail Visibly From Anywhere
Some people recommend making your software robust by working around problems automatically. This results in the software “failing slowly.” The program continues working right after an error but fails in strange ways later on. A system that fails fast does exactly the opposite: when a problem occurs, it fails immediately and visibly.
This quote is from Jim Shore’s great article “Fail Fast” (Published by the IEEE Computer Society). Although published 15 years ago, it is still very relevant today.
Fail, don’t fix 🙅
First of all, you have to accept failure. When you receive invalid or incomplete input, don’t try to work around it or assume — just fail. Fail as soon as possible.
A pattern I’ve adopted to deal with this, is the Guard pattern. Consider the following Action on an ASP.NET Core Controller:
From the get-go, it’s obvious what the Guards are for. Before handling the request, we make sure that both inputs are valid:
id should not be an empty Guid and
name should not be null or an empty string.
Initially, this is what my Guard statements looked like:
Easy enough: when a certain condition isn’t met, an Exception is thrown and further execution of the code stops — in other words: failing. Note that these Guards are the first statements in our
Post action: we’re failing fast.
There’s one problem here though: we’re throwing exceptions, which will ultimately result in our API returning
500: Internal Server Error when left unhandled. That’s not right: I didn’t do anything wrong, you did!
You got a Bad Request there, man
Our API should ideally be returning a
400: Bad Request error. After all, the request isn’t valid!
The first step is to introduce a new type of exception, a
Let’s update our Guards to throw GuardExceptions:
Now, to return a Bad Request error. Well, by the grace of exception-handling middleware in ASP.NET Core, we can add custom middleware to our request pipeline that listens for, and acts upon, these GuardExceptions.
Here’s what that looks like in our
Admittedly, this code looks a bit clunky and verbose — I hope we will see some syntactic sugar for this in a future release of ASP.NET Core.
Essentially, what happens is this: we add a custom ExceptionHandler to our pipeline. In that handler, we request the
IExceptionHandlerPathFeature feature (you can read more about ASP.NET Core Application Parts here) of ASP.NET Core.
Using some sweet C# pattern matching, we check whether the Error (if any) in the
IExceptionHandlerPathFeature is a
GuardException. If so, we return a
BadRequest along with a JSON object comprising the faulty argument and a helpful message.
And that’s it! What I really like about these Guards is that they’re concise, their intent is clear and I can drop them anywhere in my code. When left unhandled, my API will appropriately return a
Keeping it clean
Time for some shameless self-promotion: I’d strongly advise to keep this exception-handling code out of your
Startup.cs and refactor it into an extension method. You can read more about this in my story Keeping Your ASP.NET Core Startup Project Clean.
👏 Thank you for reading this!👏