Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

Overriding JSON Serializer in Giraffe

5.00/5 (2 votes)
23 Dec 2021CPOL1 min read 4.3K  
Way to leverage custom serializer in Giraffe framework
In some cases, a built-in Giraffe JSON serializer might be insufficient. In this short tip, we show how to override it.

I use my side-project KyivStationWalk as a set of my opinionated takes on software architecture. No wonder I use F# here. One of the types I use in this project to describe my domain is the subway station branch. There are 3 branches in Kyiv named by their traditional colors.

F#
type Branch =
    | Red
    | Blue
    | Green

By default Giraffe, the framework which I use as a web server, uses Newtonsoft.Json to serialize results to JSON. However, for discriminated union, it generates quite a lot of JSON so I’ve switched to System.Text.Json which is built into newer versions of .Net Core. In combination with FSharp.SystemTextJson package allows serializing discriminated unions more gracefully. All we need is to decorate Branch type with JsonFSharpConverter(JsonUnionEncoding.BareFieldlessTags) attribute.

Here’s an example of a serialized subway station. Pay attention to how neat looks branch property.

JSON
{
    "id": "5c2e1d0c867a6335386700d9",
    "name": {
        "en": "Svyatoshyn",
        "ua": "Святошин"
    },
    "branch": "Red",
    "location": {
        "lattitude": 50.457903,
        "longitude": 30.390614
    }
}

But there is a downside. Since the default serializer is Newtonsoft.Json you have to bake in serialization into your request handlers. (please note that logging and error handling is omitted for brevity)

F#
let getApproved =
    fun next httpContext ->
    task {
        let! routes = DbAdapter.getApprovedRoutes |> Async.StartAsTask
        let domainRoutes = DbMappers.dbRoutesToRoutes routes
        let result = RouteModels.toShortRoutes domainRoutes
        let serialized = JsonSerializer.Serialize(result, Common.serializerOptions)
        return! text serialized next httpContext
    }

Luckily enough Giraffe allows overriding serializer in order to use native json instead of text. In order to achieve this, you have to register the serializer of your choice in ASP.NET Core services registration section

F#
let configureServices (services : IServiceCollection) =
    services.AddGiraffe() |> ignore
    services.AddSingleton<Json.ISerializer>(SystemTextJson.Serializer(Common.serializerOptions)) |> ignore

With this done we are now able to ditch serialization logic resulting in a cleaner handler

F#
let getApproved =
    fun next httpContext ->
    task {
        let! routes = DbAdapter.getApprovedRoutes |> Async.StartAsTask
        let domainRoutes = DbMappers.dbRoutesToRoutes routes
        let result = RouteModels.toShortRoutes domainRoutes
        return! json result next httpContext
    }

History

23rd December 2021 - published initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)