Need help. With some code from Scott Wlaschin "Domain Driven Design made functional book"

Hello all!
I have been stuck with this function “validateOrder” for a while ". This portion of code is from the “Domain Driven Design made functional (Scott Wlaschin)”.
I tried to post my issue on Prag Prog “The website where I got the book from”; but it looks like some legislation in the USA has caused them to make the forum unavailable.

Bellow is the piece of code that seems not to be working:

let validateOrder : ValidateOrder =

fun checkProductCodeExists checkAddressExists unvalidatedOrder ->

printfn "IN validate order unvalidatedOrder = %A" unvalidatedOrder

printfn "IN validate order unvalidatedOrder.OrderId = %A" unvalidatedOrder.OrderId

asyncResult {

    //printfn "IN validate order customerInfo = %A" customerInfo

    let! orderId = 
        unvalidatedOrder.OrderId 
        |> toOrderId
        |> AsyncResult.ofResult

    printfn "orderId = %A" orderId

    let! customerInfo = 
        let unvalidateCustomerInfo = unvalidatedOrder.CustomerInfo 
        unvalidateCustomerInfo
        |> toCustomerInfo
        |> AsyncResult.ofResult

    let! checkedShippingAddress = 
        let unvalidateShippingAddress = unvalidatedOrder.ShippingAddress 
        unvalidatedOrder.ShippingAddress 
        |> toCheckedAddress checkAddressExists

    let! shippingAddress = 
        checkedShippingAddress 
        |> toAddress 
        |> AsyncResult.ofResult
    let! checkedBillingAddress = 
        unvalidatedOrder.BillingAddress 
        |> toCheckedAddress checkAddressExists
    let! billingAddress  = 
        checkedBillingAddress
        |> toAddress 
        |> AsyncResult.ofResult
    let! lines = 
        unvalidatedOrder.Lines 
        |> List.map (toValidatedOrderLine checkProductCodeExists) 
        |> Result.sequence // convert list of Results to a single Result
        |> AsyncResult.ofResult

    let validatedOrder : ValidatedOrder = {
        OrderId  = orderId 
        CustomerInfo = customerInfo 
        ShippingAddress = shippingAddress 
        BillingAddress = billingAddress  
        Lines = lines 
    }




    return validatedOrder 
}

This instruction

let! orderId =
unvalidatedOrder.OrderId
|> toOrderId
|> AsyncResult.ofResult

runs the unvalidatedOrder.OrderId
|> toOrderId …

function with no problem then it gets stuck at

             |> AsyncResult.ofResult.

I would appreciate if you could help me figure out what the issue is with
AsyncResult.ofResult as I feel like it is there that everything is stuck. I am available to porvide more details in case it’s needed

How is it getting stuck? Is it a runtime issue, or is the compiler/typechecker complaining? Also, what’s the error message?

let! orderId =
unvalidatedOrder.OrderId
|> toOrderId
|> AsyncResult.ofResult

printfn "orderId = %A" orderId

I think it is a runtime issue. The <<printfn “orderId = %A” orderId>> line does not execute although the “toOrder” function execute successfully. I suspect the AsyncResult.ofResult is not working as expected. Below is what the code for the AsyncResult.ofResult function looks like:

module AsyncResult =

let ofResult x : AsyncResult<_,_> = 
    x |> Async.retn

Please let me know if you need more clarifications.

This is going to sound silly, but did you try “running” it? Async's are lazy, and they need to be scheduled before they do anything. For testing purposes, try piping the result of validateOrder into Async.RunSynchronously. Eg.

asyncResult {

    //printfn "IN validate order customerInfo = %A" customerInfo

    let! orderId = 
        unvalidatedOrder.OrderId 
        |> toOrderId
        |> AsyncResult.ofResult

    printfn "orderId = %A" orderId
    
    ... 
    return validatedOrder
}
|> Async.RunSynchronously

As for what could be going wrong, it’s hard to tell without the full context. My first guess would be that the result of the toOrder stage is Result.Error. I usually debug computation expressions by removing the bang !, adding type constraints, and using printfn.

For starters, try adding explicit types to your ofResult function and see if the type checker complains:

let ofResult (x:Result<_,_>) : AsyncResult<_,_> = x |> Async.retn // I'm assuming this does the same thing as async.Return.

(Note: I’m not familiar with the Async.retn function. I’m assuming it does the same thing as async.Return. If you implemented Async.retn yourself, you might consider swapping it out for async.Return to see if this fixes the problem.)

Next, you can revise this to see if it outputs what you expect:

let orderResult : Result<_,_> =
    unvalidatedOrder.OrderId
    |> toOrderId

// This should be Result.OK
printfn "orderResult: %A" orderResult

// Ensure the following typechecks
let asyncOrderResult : AsyncResult<_,_> =  orderResult |> AsyncResult.ofResult

let! orderId = asyncOrderResult
printfn "orderId = %A" orderId

If all is working as expected (up until the let!), then it the problem could be the implementation of the AsyncResult builder. Did you write this yourself, or are you using a reference implementation?

Thanks for getting back to me so quickly.

First I tried to run the computation expression block (asyncResult { … } |> Async.RunSynchronously ) as you suggested but I got the following compiler error

"This expression was expected to have type ‘AsyncResult<ValidatedOrder,ValidationError>’ but here has type ‘Result<ValidatedOrder,ValidationError>’ … "

Then I verify that this instruction

    unvalidatedOrder.OrderId 
    |> toOrderId

was returning a Result.OK by adding the following code

let! orderId =
let testToOrderId = unvalidatedOrder.OrderId |> toOrderId
printfn “testToOrderId = %A” testToOrderId
testToOrderId
|> AsyncResult.ofResult

        printfn "orderId = %A" orderId

The result I got was: testToOrderId = Ok OrderId “1”

Then I added explicit type to

let ofResult (x:Result<,>) : AsyncResult<,> = x |> Async.retn

as you suggested and that still did not work.

I then replaced Async.retn with async.Return that still did not fix the issue.

let ofResult (x:Result<_,_>) : AsyncResult<_,_> = x |>  async.Return

Last I revised my outputs and

let orderResult : Result<_,_> =
unvalidatedOrder.OrderId
|> toOrderId 

printfn "orderResult: %A" orderResult 

does print Ok OrderId “1”

The instruction

  let asyncOrderResult : AsyncResult<_,_> = orderResult |> AsyncResult.ofResult 

Does not complain about the types

But this instruction

 let! orderId = asyncOrderResult
 printfn "orderId = %A" orderId

does not execute the whole flow just hang there (Meaning the printfn does not execute)

Do you mind taking a look at the full code at this repo? I think having the full context will be helpfull.

Git Repo Link:

git@github.com:elberto2008/app-suave-ionide-template-ubuntu.git.

The code is just one workflow (Place Order) that I am trying to execute by making a rest call to the place-order api.

Once you install the reference libraries, Suave and Newtonsoft Json , you can just navigate to the “AppSuaveFsharpIonide” folder and run “dotnet run”. It will start a web server on port 8085.
Then you can make a post to

http://localhost:8085/place-order

with the following body:

{
 "OrderId":"1",
 "CustomerInfo":{"FirstName":"Felix","LastName":"Fotio","EmailAddress":"felix@gmail.com"},
 "ShippingAddress":{"AddressLine1":"addr line 1","AddressLine2" : "addr line 2","AddressLine3" : "addr line 
  3","AddressLine4" : "addr line 4","City" : "Denver","ZipCode" : "80209"},
 "BillingAddress":{"AddressLine1":"addr line 1","AddressLine2" : "addr line 2","AddressLine3" : "addr line 
  3","AddressLine4" : "addr line 4","City" : "Denver","ZipCode" : "80209"},
 "Lines":[{"OrderLineId" : "1", "ProductCode" : "M1234",  "Quantity" : 20}, {"OrderLineId" : "2", "ProductCode" 
 : "W1234",  "Quantity" : 30}, {"OrderLineId" : "3", "ProductCode" : "W1234",  "Quantity" : 500}]
}

Please let me know if you have any questions

Thanks,

Assuming that toOrderId is returning a validation result, then you need just to wrap it in Async (async.Return) as Horace suggested. If that doesn’t work (check again) I assume that is a validation result issue (single error vs a collection of errors) - check the types in your expression. If you can’t figure it out, call me on skype at mecu.sorin

2 Likes

Hello MecuSorin,
Just wanted to check with you what time works for you.
Thanks,

I see what’s going on, here. This is a pretty subtle bug, but it has to do with the way you were invoking placeOrderApi. It wasn’t actually being “executed” completely. Here’s the offending line of code:

Filters.POST >=> request (getLocalRequestFromReq >> placeOrderApi >> JSON)

Here’s what happened:

  1. getLocalRequestFromReq parsed the incoming Suave HttpRequest into your own local HttpRequest type (the naming alias made this a little confusing for me.)
  2. This local HttpRequest was passed into placeOrderApi, which returns an Async<HttpResponse>
  3. This Async<HttpReponse> value was being passed into JSON, which should serialize the value and return a webpart that can be plugged into the request()

During step two, placeOrderApi partially executes, but it’s never actually “run” in the Suave async context. It just returns an Async<HttpResponse> instead of the result of the async computation: HttpReponse. Suave was probably scheduling this Async, but it would never return once the computation expression encountered the first let!, which is why the request never reaching your print statement.

The solution is simple, but it’s one of the things that people get hung up on with Suave. You need to make a Suave WebPart to plug into your route tree. I split the WebPart into its own function (rather than implementing it as a lambda) so you can see what it’s doing:

// our very own WebPart!
let handlePlaceOrderRequest ctx = 
    async { 
        // parse the incoming Suave HttpRequest
        let lreq = getLocalRequestFromReq ctx.request 
        // execute placeOrderApi
        let! res = placeOrderApi lreq 
        // pass the result of the computation into the JSON webpart and return
        return! ctx |> JSON res
    }
    
let rest restResourceName resource = 
    let resourcePath = "/" + restResourceName
    path resourcePath >=> choose [
        Filters.POST >=> handlePlaceOrderRequest 
    ]

This is the tricky part: return! ctx |> JSON res. The thing to grock is that suave WebParts are actually functions that take an HttpContext and return and Async. JSON is a WebPart “builder” that takes any old object, serializes it, and returns a new webpart that sets the response body. So when we pass our placeOrderApi result to JSON, we’re in a bit of a predicament. We’re already inside the async context of our handlePlaceOrderRequest WebPart. How do we execute the JSON WebPart? We’ll, we can pass the original ctx to it and then evaulate the Async<_> result. That’s why we’re using return!, here. It “executes” the async result of JSON

You’re probably thinking, “I don’t want to write a webpart like handlePlaceOrderRequest for every one of my rest endpoints!” What I recommend is factoring out the placeOrderApi computation and making it a parameter instead:

let handleApiRequest apiHandler ctx = // apiHandler can be any async api handler like placeOrderApi
    async { 
        let lreq = getLocalRequestFromReq ctx.request 
        let! res = apiHandler lreq 
        return! ctx |> JSON res
    }
    
let rest restResourceName resource = 
    let resourcePath = "/" + restResourceName
    path resourcePath >=> choose [
        Filters.POST >=> handleApiRequest placeOrderApi
    ]

Hopefully this helped. :slight_smile:

2 Likes

Thank you very much for your help. That was the problem. :slight_smile: