-
Notifications
You must be signed in to change notification settings - Fork 309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Question] How to handle different Error types in railway chain #553
Comments
Hi, yeap, that's kind a common issue. Regarding your ways to solve it:
So how to handle this situations: // 1. you want to return BadRequestError as error type
var result = service.Find("id") //Result<User?, NotFoundError>
.MapError(MapNotFoundErrorToBadRequestError) //Result<User?, BadRequestError>
.Check(user => service.UpdateAge(user, 20)); //UnitResult<BadRequestError>
// 2. you want to return NotFoundError as error type
var result = service.Find("id") //Result<User?, NotFoundError>
.Check(user => service.UpdateAge(user, 20).MapError(MapBadRequestErrorToNotFoundError)); //UnitResult<NotFoundError> And I have just a couple of thoughts about the general design:
|
Hello, If you do now want to map errors, then another way to solve this problem is as follows: public enum ErrorCodes
{
NotFound = 400,
BadRequest = 501
}
public record ServiceError(ErrorCodes Code, string Message);
class UserService()
{
public void DoTest()
{
var result = Find("id")
.EnsureNotNull(new ServiceError(ErrorCodes.BadRequest, "User data not present"))
.Check(user => UpdateAge(user, 20));
}
public Result<User?, ServiceError> Find(string id)
{
return Result.Failure<User?, ServiceError>(new ServiceError(ErrorCodes.NotFound, "User not found"));
}
public UnitResult<ServiceError> UpdateAge(User user, int age)
{
return UnitResult.Failure(new ServiceError(ErrorCodes.BadRequest, "Age is invalid"));
} Instead of public record ServiceError(ServiceError Error, string Message); |
@rutkowskit If I'm not mistaken, your approach is pretty similar to my first suggestion, isn't it? |
Yes. If you need to keep information about the error type or error code, then this approach allows it. You will not lose the ‘error type’ between steps. |
@hankovich thanks for your quick reply. I totally agree with your two thoughts at the end. This was just some demo code I quickly wrote down to show the problem in this issue. Maybe not the best demo code 😄 The drawback of your suggestion is that I have to choose one of the errors which gets returned by the chain. For context: This way you could write the following in your endpoint: return service.Find("id") //Result<User?, NotFoundError>
.ToOkHttpResult(); //Results<Ok<User>, NotFound> In case the result is a success, the method would return Now if I have this code: return service.Find("id") //Result<User?, NotFoundError>
.Check(user => service.UpdateAge(user, 20)); //UnitResult<BadRequestError>
.ToOkHttpResult(); //Results<Ok<User>, NotFound, BadRequest> I would like the method to return But I can't use If I abstract the errors using the error switch //IError
{
NotFoundError notFoundError => TypedResults.NotFound(),
BadRequestError badRequestError => TypedResults.BadRequest(),
} |
Any news on that? |
Since CSharpFunctionalExtensions supports a custom error type other than
string
via theResult<T,E>
type, I was wondering how to handle different error types in a result chain because there can be only one type forE
.Lets say I want to update a user.
I have a Service with those methods:
So both methods return different errors.
In my endpoint I'd like to do that:
But it's not possible because of the different error types.
Does anyone has an idea how to handle these use cases?
At the moment I can think of three ways on how to solve this.
First: Abstract all error types via an interface and use the abstract type in the chain.
When all error types implement
IError
I could do something like this:Second: I could use another library like OneOf that provides support for union types.
Then the Result type in the chain would be
Result<T, OneOf<NotFoundError,BadRequestError>>
.But that seems to make problems because inside the
Bind
method theNotFoundError
cannot be implicitly casted toOneOf<NotFoundError, BadRequestError>
.Third: A big chain ist not possible. I rather have to split the chain each time the error type changes. On the split I have to check the
.IsFailure
property on the result. Handle the error case and otherwise start a new chain with the previous value and new error type.The text was updated successfully, but these errors were encountered: