Reputation: 3832
In my .NET Core Web API project many controller endpoints have code like this example
public async Task<ActionResult<User>> UpdateUserUsernameAsync(/* DTOs */)
{
try
{
User user = null; // Update user here
return Ok(user);
}
catch (EntityNotFoundException entityNotFoundException) // map not found to 404
{
return NotFound(entityNotFoundException.Message);
}
catch (EntityAlreadyExistsException entityAlreadyExistsException) // map duplicate name to 409
{
return Conflict(entityAlreadyExistsException.Message);
}
catch (Exception exception) // map any other errors to 500
{
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
I would like to create a mapping for the controllers that catches exceptions and maps them to HTTP responses before sending them back to the client.
A similiar question has been asked 4 years ago
ASP.NET Core Web API exception handling
In NestJs it's possible to define your own mappings by extending a base class e.g.
export class MyCustomException extends HttpException {
constructor() {
super('My custom error message', HttpStatus.FORBIDDEN);
}
}
Taken from here https://docs.nestjs.com/exception-filters#custom-exceptions
So basically I want to define mapping classes that could look like this sample code (this just shows my pseudo implementation)
// Map MyCustomException to NotFound
public class MyCustomExceptionMapping<TCustomException> : IExceptionMapping<TCustomException>
{
public ActionResult Map(TCustomException exception)
{
return NotFound(exception.Message);
}
}
Next I can cleanup the controller endpoint method to
public async Task<ActionResult<User>> UpdateUserUsernameAsync(/* DTOs */)
{
User user = null; // Update user here
return Ok(user);
}
Whenever an exception gets thrown the API would try to find the correct mapping interface. Otherwise it sends back a 500.
It would be nice to define such mappings and avoid a huge switch case for every exception in your project.
Does something like this exists? Is the accepted answer from the previous question still up to date?
Upvotes: 0
Views: 1413
Reputation: 1020
Use Exception Filters it will be called when the controller throws an Exception and you can define the custom response. Microsoft Docs
public class MyExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
HttpStatusCode status;
var message = "";
var exceptionType = context.Exception.GetType();
if (exceptionType is EntityNotFoundException)
{
status = HttpStatusCode.NotFound;
message = context.Exception.Message;
}
else if (exceptionType is EntityAlreadyExistsException)
{
status = HttpStatusCode.Conflict;
message = context.Exception.Message;
}
else
{
status = HttpStatusCode.InternalServerError;
message = "Internal Server Error.";
}
//You can enable logging error
context.ExceptionHandled = true;
HttpResponse response = context.HttpContext.Response;
response.StatusCode = (int)status;
response.ContentType = "application/json";
context.Result = new ObjectResult(new ApiResponse { Message = message, Data = null });
}
}
To use the filter on all controllers you must register it in the ConfigureServices method in the Startup.cs
services.AddMvc(config =>
{
config.Filters.Add(typeof(MyExceptionFilter));
})
Upvotes: 4