Quick and friendly feedback

Thoth.Json reports helpful errors. Stop wasting time searching why your JSON is invalid.

Error at: `$.user.firstname`
Expecting an object with path `user.firstname` but instead got:
{
    "user": {
        "name": "maxime",
        "age": 25
    }
}
Node `firstname` is unknown.

Build with small blocks

Thoth.Json allows you to work on small functions and then combine them into a bigger one making it easy to handle complex data.

module Author =
    let decoder =
        Decode.object (fun get ->
            {
                Name = get.Required.Field "name" Decode.string
                Profile = get.Required.Field "profile" Decode.string
            }
        )

module Post =
    let decoder =
        Decode.object (fun get ->
            {
                Title = get.Required.Field "title" Decode.string
                Abstract = get.Required.Field "abstract" Decode.string
                Date = get.Required.Field "date" Decode.datetime
                Author = get.Required.Field "author" Author.decoder
            }
        )

Isomorphic support

If you use F# on the server and client, you can directly use your F# types to define your JSON.

type User =
    {
        Email : string
        Firstname : string
    }

let user =
    {
        Email = "maxime@mail.com"
        Firstname = "Maxime"
    }

// Transform your F# types to JSON
let userJson =
    Encode.Auto.toString(4, user)

// Transform your JSON to F# types
let userFromJson =
    Decode.Auto.fromString<User> userJson

Extensible

Extends Thoth.Json with your own decoders and encoders.

module Encode =

    let timestamp (date : DateTime) =
        DateTimeOffset(date).ToUnixTimeSeconds()
        |> box

module Decode =

    let timestamp : Decoder<DateTime> =
        fun path value ->
            if Decode.Helpers.isNumber value then
                let value : int64 = unbox value
                let datetime =
                    DateTimeOffset
                        .FromUnixTimeSeconds(value)
                        .DateTime
                Ok datetime

            else
                (path, BadPrimitive("a timestamp", value)) |> Error

// Example: decode an invalid JSON
Decode.fromString Decode.timestamp "\"2022-01-01\""

// Error at: `$`
// Expecting a number but instead got:
// "2022-01-01"