Skip to content

1. Getting Started

percyqaz edited this page Jul 6, 2021 · 2 revisions

Quick start

To get started, first create an instance of JsonEncoder like this:

open Percyqaz.Json

let json = new JsonEncoder(JsonSettings.Default)

JsonSettings is a record containing settings for the encoder You can read more about this and the settings available here.


JsonEncoder comes with the following methods:

.ToJson : 'T -> JSON - The JSON type is the representation of JSON data as a discriminated union. This method takes an object of any type, and if it can create a codec for it, it will translate it into JSON data.

.ToString : 'T -> string maps an object of any type directly to a JSON formatted string.

.ToStream : System.IO.Stream -> 'T -> unit writes the JSON formatted string of an object directly to a stream.

.ToFile : (path: string * overwrite: bool) -> 'T -> unit writes the JSON formatted string directly to a given file path. If overwrite is true, this will always overwrite a file if it exists, otherwise an error is thrown if the file already exists.

.FromJson<'T> : JSON -> JsonResult<'T> - JsonResult<'T> is an alias for Result<'T, Exception> and is either an Ok of the desired result or an Error of the error that occurred while decoding. The function takes JSON data and attempts to map it to the given type 'T.

.FromString<'T> : string -> JsonResult<'T> parses the string as JSON and then attempts to map it to the given type 'T

.FromStream<'T> : (nameOfStream: string * stream: System.IO.Stream) -> JsonResult<'T> parses JSON string from stream and maps it to 'T. nameOfStream indicates a name/source for the stream for use in FParsec errors that can tell you exactly which part of the stream had a syntactic error.

.FromFile<'T> : string -> JsonResult<'T> parses a file as JSON and maps it to 'T. If the file is not found this does not throw an exception, but instead is returned as a FileNotFoundException inside the JsonResult

.Default<'T> : unit -> 'T will generate a default instance of 'T. This instance is perfectly valid in F# (not null, no members of it are invalid, etc), it is completely safe to be consumed by ordinary F# code.

All 9 of the methods above can throw a runtime exception if no codec can be generated for the type given. This truly is an exception/fail case as it is expected that you have a codec rule in place for all the types you plan to be encoding/decoding.

.AddRule : Mapping.CustomCodecRule -> unit will add a new rule to the encoder on what to do when handling certain types. You can read more about this here but we'll come back to this later.

Basic examples:

open Percyqaz.Json

let json = new JsonEncoder(JsonSettings.Default)

// many types work out of the box!

json.ToString 2 // 2

json.ToString ("Hello", 20.0f, '\n') // ["Hello", 20.0, "\n"]

json.FromString<{|a: byte; b: int option|}> """{ "a": 36, "b": null }""" // {| a = 36uy; b = None |}

Without providing any custom rules, there is support for:

  • All integer types, booleans, float, double and decimal
  • Strings and chars
  • Arrays, lists (F# and C#), dictionarys/maps (F# and C#)
  • (Value) Options, (struct) tuples, (struct) discriminated unions
  • (struct) Records (including anonymous records)

Record example:

type MyRecord =
    {
        hello: string
        world: int
    }
    static member Default =
        {
            hello = "Hello world!"
            world = -1
        }

Defining a Default instance of records like this is recommended - It provides defaults for every member of the record for the codec generator to use as reference when values are missing.

json.Default<MyRecord>() calls MyRecord.Default and returns it. Note: MyRecord.Default is a getter property, and so constructs a new instance of MyRecord each time it is called!

Mapping to MyRecord from JSON will construct the default instance, and then replace any members it can with members it can decode from the JSON.

Example:

json.FromString<MyRecord> "{}" // { hello = "Hello world!"; world = -1 }

json.FromString<MyRecord> """{ "world": 5 }""" /// { hello = "Hello world!"; world = 5 }

// error recovery if member cannot be decoded
json.FromString<MyRecord> """{ "world": null }""" /// { hello = "Hello world!"; world = -1 }

If you do not provide a default instance, or mark your record with [<Json.AllRequired>], having missing/invalid members in your JSON will cause a mapping failure. (Extra members in your JSON will be ignored in all cases)

You can mark individual members of your records with [<Json.Required>] to make a successful decode of that member necessary for a successful decode of the record.

Clone this wiki locally