0

I am just starting with language-ext, trying to use it in my Azure Function.

In this function, I first parse/validate the POSTed data from the HTTP request using some validator. This validator returns an Either<ValidationErrors, RequestModel>. Then I would like to chain onto the either result a service call that should use the request model to grab some data from an API an return an Option. At the end of the chain I would then like to return an IActionResult BadRequest if there were ValidationErrors in the first step, or otherwise perform a Match on the result of the service call Option to either return a NotFoundResult or ObjectResult.

The issue I run into is that if I want to chain my service call (using Bind, or BiBind) after the Either<ValidationErrors, GetRequestModel>, then the signature of my service method must be some Either<ValidationErrors, ...>, which is incorrect, since my service method has nothing to do with ValidationErrors. It should just return an Option.

So I guess my question is how can preserve any ValidationErrors until the end of the chain, and be able to chain my service call with a Option signature onto an Either?

Para Jaco
  • 211
  • 2
  • 9

1 Answers1

0

You have to decide what the result of your chained expression is.

Option:

var maybeResult = from validated in GetValidationResult(...).ToOption()
                  from apiResult in ApiCall(...)
                  select apiResult;

Either:

var resultOrError = from validated in GetValidationResult(...)
                    from apiResult in ApiCall(...).ToEither(*LEFT*)
                    select apiResult;

You have to replace *LEFT* by some error value or error generating function returning same type like left type of GetValidationResult.

Replace above pseudo code with your own code and look at the return types of the functions used above to see what's going on.

The reason why you need a common left type is that the bind operation can return some left (error) of first (GetValidationResult) or second (ApiCall) function call -- or right of your last (ApiCall) function if your reach successful end of your chain.

Recommendation: If you mix different left (error) return types you might want to use some thing like LanguageExt's built-in Error type or maybe just a plain string (or Exception).

Either with string as error type:

var resultOrError = from validated in GetValidationResult(...).MapLeft(Prelude.toString)
                    from apiResult in ApiCall(...).ToEither("api call failed")
                    select apiResult;

Additional note: I use LINQ style here, you can use method style:

var resultOrError = GetValidationResult(...)
                    .MapLeft(Prelude.toString)
                    .Bind(validated => ApiCall(...)
                                       .ToEither("api call failed"));

stb
  • 772
  • 5
  • 15
  • Thanks @stb for the answer. Based on your response it was clear how to proceed. In the end I used something like the following code to perform request model creation, validation, call my service, and generate a response. I am using an Either in my flow. Within the Errors, I remember if it was validation errors or not. Then in the end when I match the result to a IActionResult, I convert the Errors to an IActionResult using the validation property. When the errors are validation errors I create a BadRequest result, otherwise I create a InternalServerError result. – Para Jaco Jun 30 '21 at 10:32