ChilliCream / graphql-platform

Welcome to the home of the Hot Chocolate GraphQL server for .NET, the Strawberry Shake GraphQL client for .NET and Banana Cake Pop the awesome Monaco based GraphQL IDE.
https://chillicream.com
MIT License
5.03k stars 724 forks source link

Support F# Async<_> expressions #7023

Open cmeeren opened 2 months ago

cmeeren commented 2 months ago

Product

Hot Chocolate

I think this request is conceptually fairly simple - it just requires a trivial wrapper.

As we all know, HotChocolate has built-in support for Task<_>. The following works fine:

type Query() =

    member _.GetFoo([<Service>] fooRepo: FooRepository, cancellationToken) : Task<Foo> =
        task {
            let! foo = fooRepo.GetFoo(cancellationToken)
            return foo
        }

However, in F#, we generally use Async<_> instead of Task<_>. This has several benefits, such as implicit cancellation token passing, better composability, etc. The following is how I ideally would like to write this, but it does not work, since HotChocolate does not know about Async:

type Query() =

    member _.GetFoo([<Service>] fooRepo: FooRepository) : Async<Foo> =
        async {
            let! foo = fooRepo.GetFoo()
            return foo
        }

However, simply by wrapping the async computation in Async.StartImmediateAsTask (and passing the cancellation token from HotChocolate), it works as expected:

    member _.GetFoo([<Service>] fooRepo: FooRepository, cancellationToken) : Task<Foo> =
        let comp =
            async {
                let! foo = fooRepo.GetFoo()
                return foo
            }

        Async.StartImmediateAsTask(comp, cancellationToken)

This is a simple workaround, but it's a drag to have to do in it every async resolver. I would like HotChocolate (possibly in HotChocolate.Types.FSharp or another F#-oriented package) to do this for me. That way, the middle of the three code snippets above would work out of the box.