The best way to handle Errors in Clean Arch
Hello, everything okay? I have a question. I want to know what is the best way to handle errors in my application using Clean Architecture. To put you in context, I am creating a layered API, that is, there is the Infrastructure that contains the repository and the application layer that contains the service. The logic goes in the service, for example, when a user registers and their username has at least 6 characters, then it throws an error that is ArgumentException with a message:
Now, in the controller, what is the best way to handle those errors? Why does it always return a status code of 500, while the error could be 401? Also, how do I resolve the message? Thank you so much. I leave you images so that you can put yourself in context.
21 Replies
MemberService
Controller
You can create error handling middleware
GitHub
Forum/backend/Forum.WebApi/Middlewares/CustomExceptionHandlerMiddle...
Contribute to TarasKo444/Forum development by creating an account on GitHub.
Example of my error handling
You need to add this middleware before routing and just use throw
And you better make your own exception with status code in it like i did
THANKS
Thats certainly one way, and its a good way to make sure no exceptions go unlogged (I use such a middleware to make sure any request->response pipeline that fails gets properly logged in Seq).
It has a minor downside thou - now your business logic is suddenly HTTP aware. Personally, I like to keep my business logic away from protocol specific awareness when possible. An example is that your service method needs to know that it should throw a very specific exception that will leads to a 403.
My personal solution to this is that my "services" (I don't use service objects, they are too similar to god-classes for my tastes) instead return stronly typed result objects, and the endpoints (controller actions or similar) handle the business error -> HTTP conversion.
What do u do when u need to get authorised user id in application layer
Do u use httpcontext accessor or pass id through request
access the http context in your endpoint and pass the correct user object down into the handler
Do not hear the moment you handle it and decide the statusCode. Siempre returned 500, no?
.
That's exactly what I mean. My service is in the Application layer, I don't want it to return a BadRequest, since that is from API and Http. I am a Typescript backend programmer in Nodejs, and before, I did what you mentioned, that is, returning an object with a message and its StatusCode. Is it functional? Does it belong to Clean Arch? Is there any other alternative?
I'm reading the message again and you understood me perfectly lol
Can we make a call so can you help me? I'm new and I can't figure out how to do it. Because I have many services, and for example, in the users service, I want to return a JSON object of this style:
{
statusCode: ...,
message: ...,
[MODEL]
}
The [MODEL] depends on the service. In the example I am giving you, the Model would be the UserDTO
I don't know what would be the best way to make a general contract between all the services to return that JSON
It returns 500 if thrown error wasn't ApiException
Otherwise it will take code from the ApiException
Do u have a github rep with example?
Sadly not. But its fairly simple
Exactly how to implement it depends on what
Result
library you use, since its not a standard thing. My personal preference is Remora.Result
(made by our very own Jay), but OneOf
is probably more familiar for a Typescript developer, and there is also ErrorOr
and Rascal
(made by our very own Thinker).
https://github.com/Remora/Remora.Results
https://github.com/mcintyre321/OneOf
https://github.com/amantinband/error-or
https://github.com/thinker227/Rascal
Either of these are fine.
something like this, with Remora
The pattern itself works fine without a mediator or a mapper, but those are things I personally like usingSo the object mediator return is something like Results<TResponse> where Results have properties like
Error error
bool isSuccess
TResonse Entity?
yeah, something like that
https://github.com/thinker227/Rascal/blob/main/src/Rascal/Result.cs
look here for an example
this is Rascal, but the same concept applies
solution seems pretty good
yeah I like it
you could replace the mediator.Send call with your service and method, if you prefer that pattern
I strongly recomend using dtos and a mapper of some sort (manual is fine too) thou, to prevent oversharing
I think i can combine both this and middleware
you can.
I use the middleware to log exceptions, and "this" to handle my errors
unexpected exceptions sometimes leak through to the middleware, which is exactly what its purpose is
Yeah, thanks for your help
You just need to be careful of returning "just any" exception in your API responses. From a security point of view, that could give an attacker valuable information.
your global exception handler should not return any information about the exception in a production setting, just "internal server error" or something similar
only in debug/qa/local mode should it expose exception details