It's common to find errors and bugs in your code if you're a software developer. They might occur because of incorrect input, from passing the wrong data types, or because of delays or response timeouts.
And even though errors and bugs are a part of life, they can stress you out and decrease your productivity. Fortunately, you can limit the number of pests in your code by taking proactive measures to prevent and fix them.
In this article, you will learn how best to utilize exception filters to limit disruptions in your code implementations.
What Are Exception Filters?
Exception filters are constructs of a programming language that help you handle exceptions or errors found in services or controller classes. Using these filters improves the efficiency of your codebase and makes errors more traceable, which helps you resolve them.
What are Exception Filters in Nest.js?
Nest.js has an inbuilt exception filter interface that you import from the @nestjs/common package
. This interface gives you precise information about exceptions you may encounter so that you can know how to fix them.
Some built-in exception filters include NotFoundException
, UnauthorizedException
, and RequestTimeOutException
, among others.
How to Create a Custom Exception Filter
To create a custom exception filter class, you define it with a @Catch
decorator that takes in the type of exception the filter should catch. This class then implements the ExceptionFilter
interface. This way you will have access to the catch
method that the interface provides.
NestJS allows you to create your own exception filters so you can define what sort of information it should return.
@Catch(HttpException)
export class TestExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
As you can see above, the catch method takes in two argument inputs: the exception:HttpException
and the host:argumentsHost
.
HttpException
is the exception thrown when an HTTP
request fails and returns the appropriate Error Message with a status code as a response to the client.
The argumentsHost
parameter provides information about the current request and response cycle. Here the code extracts the Response and Request objects from the ArgumentsHost
object using the switchToHttp
method. It then calls the getStatus
method from the HttpException
object in order to retrieve the HTTP
status code of the error.
A JSON
object gets returned. It contains the status code, the error timestamp, and the request URL, setting the HTTP
response status code to be the error status code.
Another exciting thing to note is that you can modify the status code and error message of existing exception filters like NotFoundException
so that they display your own custom error message and status code. Here is an illustration below:
export class NotFoundException extends HttpException {
constructor(message: string) {
super(message || 'Not Found', HttpStatus.NOT_FOUND);
}
}
The example above shows that the NotFoundException
class was modified to accept a message
parameter in the constructor method or give a default value of 'Not Found'.
By doing this you are now able to customize an error message for your NotFoundException
class and return a 404
status code.
How to Bind Exception Filters in Nest.js
You might be wondering how you can implement the custom or modified exception you've created for your application. Well, you use something called binding.
There are several ways in which you can bind exception filters to your application. Here are three major ways you can do it:
- Global Scope
- Controller Scope
- Method Scope
Binding using Global Scope
Just like the name “Global” implies, it covers the entirety of a thing – in this case the application. The custom exception filter is bonded to the entirety of your web application by using the useGlobalFilters()
function. An instance of your custom exception filter gets passed in before starting up the server.
Here is an example of what that looks like:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new TestExceptionFilter());
await app.listen(3000);
}
bootstrap();
If you bind the exception filter to the global scope, it means that any exceptions of type HttpException
thrown from any controller or method within the application will be handled by the TestExceptionFilter
.
Binding using Controller Scope
If you want to handle an exception that not only covers the specific methods in your application but also the entire controller with the methods in it, you can the @UseFilters
to bind the custom exception to the controller. Check out the below is example:
@UseFilters(TestExceptionFilter)
@Controller('users')
export class UsersController {
@Get()
async findUsers() {
// ...
}
}
In this example, the custom exception filter is bonded to the controller by putting it ahead of the @Controller
decorator. This way it handles any error that comes from the routes in this controller.
Binding using Method Scope
In this form of binding, you make use of the @UseFilters
decorator to apply the Custom ExceptionFilter you defined to a method in your application. Here is an example:
@Controller()
export class UsersController {
@Get()
@UseFilters(TestExceptionFilter)
async findUsers() {
// ...
}
}
In this example, you're using the @UseFilters
decorator to bind the TestExceptionFilter
exception filter to the findUsers
method. This means that if any exception occurs within the findUsers()
method, the TestExceptionFilter
will catch and handle it.
Debugging Made Easier
In this tutorial, you learned about exception filters in Nest.js, and how to create custom exception filters. You also saw some different ways in which you can implement them in your applications.
All the methods discussed are good ways to handle exceptions. By implementing these techniques, you can ensure smoother application performance and provide a better user experience.
If you enjoyed reading this article, you can share and follow me on Twitter and Linkedin.