FSharp.HotChocolate 0.1.13

dotnet add package FSharp.HotChocolate --version 0.1.13                
NuGet\Install-Package FSharp.HotChocolate -Version 0.1.13                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FSharp.HotChocolate" Version="0.1.13" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add FSharp.HotChocolate --version 0.1.13                
#r "nuget: FSharp.HotChocolate, 0.1.13"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install FSharp.HotChocolate as a Cake Addin
#addin nuget:?package=FSharp.HotChocolate&version=0.1.13

// Install FSharp.HotChocolate as a Cake Tool
#tool nuget:?package=FSharp.HotChocolate&version=0.1.13                

FSharp.HotChocolate

Support for F# types and nullability in HotChocolate.

Latest HotChocolate stable

Latest HotChocolate preview ( currently not working for HC >= 15.0.0-p.12, see #20)

Quick start

  1. Remove any existing calls to AddFSharpTypeConverters or AddTypeConverter<OptionTypeConverter>.
  2. Call AddFSharpSupport:
.AddGraphQLServer().AddFSharpSupport()

Features

FSharp.HotChocolate supports the following:

  • Idiomatic F# nullability through Option<_>
  • Async<_> fields
  • F# collection types on input
  • F# unions as GraphQL enums
  • F# unions as GraphQL unions

Idiomatic F# nullability through Option<_>

All fields defined in F# (including HotChocolate type extensions for types not defined in F#) will have idiomatic F# nullability applied. This means that everything except Option-wrapped values will be non-nullable (!) in the GraphQL schema. Any usages of [<GraphQLNonNullType>], or NonNullType<_> in [<GraphQLType>], will be ignored.

Opting out of F# nullability

Due to limitations (see below) or other reasons, you may want to opt out of F# nullability for a certain scope. You can apply the SkipFSharpNullability attribute to parameters, members, types (including HotChocolate type extensions), or whole assemblies to disable F# nullability processing for that scope.

Limitations in F# nullability
  • When using global object identification, Option-wrapped node resolvers are not supported (#5).
  • When using global object identification, Option-wrapped ID values inside lists are not supported (#6).
  • Support for ValueOption<_> is not yet added (#10).
  • When using UsePaging, the nullability of the first, last, before, and after parameters is controlled by HotChocolate. These are always nullable. Therefore, if these parameters are explicitly present in your method (e.g. if doing custom pagination), make sure you wrap them in Option<_>. The only exception is if you use RequirePagingBoundaries = true with AllowBackwardPagination = false; in that case, HotChocolate will effectively enforce that these (only) two parameters are non-null on input (even though they are nullable in the schema), and it's safe to not wrap them in Option<_> in code.

Async<_> fields

Fields can now be Async<_>.

The computations are automatically wired up to the RequestAborted cancellation token. If you do not want that, please convert the Async<_> to Task<_> yourself as you see fit.

Limitations in Async<_> fields
  • When using some built-in middleware such as [<UsePaging>], Async<_> is not supported for that field. (#8).
  • When using global object identification, Async<_> is not supported for node resolvers (#9).

F# collection types on input

Parameters and input types can now use List<_> or Set<_>.

F# unions as GraphQL enums

You can use F# fieldless unions as enum types in GraphQL, similar to how normal enums work:

type MyUnion =
    | A
    | B
    | [<GraphQLName("custom_name")>] C
    | [<GraphQLIgnore>] D

Add the type to GraphQL using FSharpUnionAsEnumDescriptor:

AddGraphQLServer().AddType<FSharpUnionAsEnumDescriptor<MyEnum>>()

It will give this schema:

enum MyUnion {
  A
  B
  custom_name
}
Customizing enums

You can inherit from FSharpUnionAsEnumDescriptor to customize the type as usual. Remember to call base.Configure in your override.

type MyEnumDescriptor() =
    inherit FSharpUnionAsEnumDescriptor<MyEnum>()

    override this.Configure(descriptor: IEnumTypeDescriptor<MyEnum>) =
        base.Configure(descriptor)
        descriptor.Name("CustomName") |> ignore

Then, use your subtype in AddType:

AddType<MyEnumDescriptor>()

F# unions as GraphQL unions

You can define an F# union type to be used as a union in the GraphQL schema:

type MyUnion =
    | A of MyTypeA
    | B of MyTypeB

(The case names are not used.)

Add the type to GraphQL using FSharpUnionAsUnionDescriptor:

AddGraphQLServer().AddType<FSharpUnionAsUnionDescriptor<MyUnion>>()

You can then return MyUnion directly through fields:

type Query() =

    member _.MyUnion : MyUnion = ...

It will give this schema:

type MyTypeA { ... }
type MyTypeB { ... }
type Query { myUnion: MyUnion! }
union MyUnion = MyTypeA | MyTypeB
Customizing unions

You can inherit from FSharpUnionAsUnionDescriptor to customize the type as usual. Remember to call base.Configure in your override.

type MyUnionDescriptor() =
    inherit FSharpUnionAsUnionDescriptor<MyUnion>()

    override this.Configure(descriptor) =
        base.Configure(descriptor)
        descriptor.Name("CustomName") |> ignore

Then, use your subtype in AddType:

AddType<MyUnionDescriptor>()
Overriding the union case types

If the default inferred types for the union cases are not correct (for example, if you have multiple GraphQL schema types for the same runtime type), you can use GraphQLTypeAttribute on individual cases to specify the correct type:

type MyUnion =
    | [<GraphQLType(typeof<MyTypeA2Descriptor>)>] A of MyTypeA
    | B of B

Acknowledgements

Many thanks to @Stock44 for creating this gist that sparked this project. Without that, I'd have no idea where to even begin.

Contributor notes

Two package versions are published: A stable version for the stable version of HotChocolate, and a pre-release version for the pre-release version of HotChocolate.

The compiler constant HC_PRE is available for conditional compilation in all projects. It is defined when building for the pre-release version of HotChocolate.

Deployment checklist

  • Make necessary changes to the code
  • Update the changelog
  • Update the versions in the fsproj files:
    • If the change only pertains to a pre-release of HotChocolate and only the pre-release package needs to be published, only adjust VersionSuffix
    • Otherwise, bump VersionPrefix and reset the last part of VersionSuffix to -001.
  • Commit and tag the commit (this is what triggers deployment):
    • If VersionPrefix was bumped, the tag should be v/<prefix> where <prefix> is VersionPrefix, e.g. v/1.0.0
    • If only VersionSuffix was bumped, the tag should be v/<prefix>-<suffix>, e.g. v/1.0.0-hc15-001
  • Push the changes and the tag to the repo. If the build succeeds, the packages are automatically published to NuGet.
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.1.13 3,473 11/22/2024
0.1.13-hc15-001 40 11/22/2024
0.1.10 200 11/18/2024
0.1.10-hc15-001 37 11/18/2024
0.1.9 596 10/19/2024
0.1.9-hc15-001 73 10/19/2024
0.1.8 264 9/25/2024
0.1.7 85 9/25/2024
0.1.6 58 9/25/2024
0.1.5 54 9/25/2024
0.1.4 61 9/24/2024
0.1.3 69 9/23/2024
0.1.2 66 9/23/2024
0.1.1 60 9/23/2024
0.1.0 64 9/23/2024