{"id":19009032,"url":"https://github.com/fsprojects/fleece","last_synced_at":"2025-04-13T07:50:37.828Z","repository":{"id":39793790,"uuid":"15757031","full_name":"fsprojects/Fleece","owner":"fsprojects","description":"Json mapper for F#","archived":false,"fork":false,"pushed_at":"2023-10-22T16:32:33.000Z","size":1956,"stargazers_count":196,"open_issues_count":25,"forks_count":30,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-05-18T21:53:17.925Z","etag":null,"topics":["codecs","json","json-mapper"],"latest_commit_sha":null,"homepage":"http://fsprojects.github.io/Fleece","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fsprojects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-01-09T04:56:36.000Z","updated_at":"2024-04-24T17:00:59.000Z","dependencies_parsed_at":"2023-01-28T09:31:09.273Z","dependency_job_id":"9154884a-036f-4d09-a16f-b8c14f51d029","html_url":"https://github.com/fsprojects/Fleece","commit_stats":{"total_commits":236,"total_committers":14,"mean_commits":"16.857142857142858","dds":0.5508474576271186,"last_synced_commit":"d98b1684b139611fe7c115956124d07efb200092"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FFleece","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FFleece/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FFleece/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsprojects%2FFleece/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fsprojects","download_url":"https://codeload.github.com/fsprojects/Fleece/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248681494,"owners_count":21144700,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codecs","json","json-mapper"],"created_at":"2024-11-08T19:06:17.686Z","updated_at":"2025-04-13T07:50:37.800Z","avatar_url":"https://github.com/fsprojects.png","language":"F#","readme":"Fleece\n======\n\nFleece is a JSON mapper for F#. It simplifies mapping from a Json library's JsonValue onto your types, and mapping from your types onto JsonValue. \n\nThe Json library could be [System.Json](http://bit.ly/1axIBoA), [System.Text.Json](https://docs.microsoft.com/en-us/dotnet/api/system.text.json), [FSharp.Data](http://fsharp.github.io/FSharp.Data/)'s or [NewtonSoft's Json.NET](https://www.newtonsoft.com/json).\n\nIts design is strongly influenced by Haskell's [Aeson](http://hackage.haskell.org/package/aeson-0.7.0.0/docs/Data-Aeson.html). Like Aeson, Fleece is designed around two typeclasses (in [FSharpPlus](https://github.com/fsprojects/FSharpPlus) style) ToJson and OfJson.\n\n### Download binaries\n* [Fleece core](https://www.nuget.org/packages/Fleece)\n* [For System.Json](https://www.nuget.org/packages/Fleece.SystemJson/)\n* [For System.Text.Json](https://www.nuget.org/packages/Fleece.SystemTextJson/)\n* [For FSharp.Data](https://www.nuget.org/packages/Fleece.FSharpData/)\n* [For NewtonSoft](https://www.nuget.org/packages/Fleece.NewtonSoftJson/)\n\n### Example\n\nFor example, given this data type:\n\n```fsharp\ntype Person = {\n    Name: string\n    Age: int\n    Children: Person list\n}\n```\n\nYou can map it to JSON like this:\n\n```fsharp\nopen Fleece\nopen Fleece.Operators\n\ntype Person with\n    static member ToJson (x: Person) =\n        jobj [ \n            \"name\" .= x.Name\n            \"age\" .= x.Age\n            \"children\" .= x.Children\n        ]\n\nlet p = \n    { Person.Name = \"John\"\n      Age = 44\n      Children = \n      [\n        { Person.Name = \"Katy\"\n          Age = 5\n          Children = [] }\n        { Person.Name = \"Johnny\"\n          Age = 7\n          Children = [] }\n      ] }\n\n// Test with System.Text.Json\n\nopen Fleece.SystemTextJson\nprintfn \"%s\" (toJsonText p)\n```\n\nAnd you can map it from JSON like this:\n\n```fsharp\ntype Person with\n    static member OfJson json =\n        match json with\n        | JObject o -\u003e\n            let name = o .@ \"name\"\n            let age = o .@ \"age\"\n            let children = o .@ \"children\"\n            match name, age, children with\n            | Decode.Success name, Decode.Success age, Decode.Success children -\u003e\n                Decode.Success {\n                    Person.Name = name\n                    Age = age\n                    Children = children\n                }\n            | x -\u003e Error \u003c| Uncategorized (sprintf \"Error parsing person: %A\" x)\n        | x -\u003e Decode.Fail.objExpected x\n        \nlet john : Person ParseResult = ofJsonText \"\"\"{\"name\": \"John\", \"age\": 44, \"children\": [{\"name\": \"Katy\", \"age\": 5, \"children\": []}, {\"name\": \"Johnny\", \"age\": 7, \"children\": []}]}\"\"\"\n```\n\nThough it's much easier to do this in a monadic or applicative way. For example, using [FSharpPlus](https://github.com/fsprojects/FSharpPlus) (which is already a dependency of Fleece):\n\n```fsharp\nopen FSharpPlus\n\ntype Person with\n    static member Create name age children = { Person.Name = name; Age = age; Children = children }\n\n    static member OfJson json =\n        match json with\n        | JObject o -\u003e Person.Create \u003c!\u003e (o .@ \"name\") \u003c*\u003e (o .@ \"age\") \u003c*\u003e (o .@ \"children\")\n        | x -\u003e Decode.Fail.objExpected x\n\n```\n\nor with applicatives:\n\n\n```fsharp\n\nopen FSharpPlus\n\ntype Person with\n    static member OfJson json =\n        match json with\n        | JObject o -\u003e \n            monad {\n                let! name = o .@ \"name\"\n                and! age = o .@ \"age\"\n                and! children = o .@ \"children\"\n                return {\n                    Person.Name = name\n                    Age = age\n                    Children = children\n                }\n            }\n        | x -\u003e Decode.Fail.objExpected x\n```\n\nOr you can use the Choice monad/applicative in [FSharpx.Extras](https://github.com/fsprojects/FSharpx.Extras) instead, if you prefer.\n\nYou can see more examples in the [EdmundsNet](https://github.com/mausch/EdmundsNet) project.\n\n\n### CODEC\n\nFor types that deserialize to Json Objets, typically (but not limited to) records, you can alternatively use codecs and have a single method which maps between fields and values. \n\n\n```fsharp\n\ntype Person = { \n    name : string * string\n    age : int option\n    children: Person list } \n    with\n    static member get_Codec () =\n        fun f l a c -\u003e { name = (f, l); age = a; children = c }\n        \u003c!\u003e jreq \"firstName\" (Some \u003c\u003c fun x -\u003e fst x.name)\n        \u003c*\u003e jreq \"lastName\"  (Some \u003c\u003c fun x -\u003e snd x.name)\n        \u003c*\u003e jopt \"age\"       (fun x -\u003e x.age) // Optional fields can use 'jopt'\n        \u003c*\u003e jreq \"children\"  (fun x -\u003e Some x.children)\n        |\u003e ofObjCodec\n        \nlet john: Person ParseResult = ofJsonText \"\"\"{\"name\": \"John\", \"age\": 44, \"children\": [{\"name\": \"Katy\", \"age\": 5, \"children\": []}, {\"name\": \"Johnny\", \"age\": 7, \"children\": []}]}\"\"\"\n```\n\n\nDiscriminated unions can be modeled with alternatives:\n```fsharp\ntype Shape =\n    | Rectangle of width : float * length : float\n    | Circle of radius : float\n    | Prism of width : float * float * height : float\n    with \n        static member get_Codec () =\n            (Rectangle  \u003c!\u003e jreq \"rectangle\" (function Rectangle (x, y) -\u003e Some (x, y) | _ -\u003e None))\n            \u003c|\u003e (Circle \u003c!\u003e jreq \"radius\"    (function Circle x -\u003e Some x | _ -\u003e None))\n            \u003c|\u003e (Prism  \u003c!\u003e jreq \"prism\"     (function Prism (x, y, z) -\u003e Some (x, y, z) | _ -\u003e None))\n            |\u003e ofObjCodec\n```\n\n\nor using the jchoice combinator:\n```fsharp\ntype Shape with\n        static member JsonObjCodec =\n            jchoice\n                [\n                    Rectangle \u003c!\u003e jreq \"rectangle\" (function Rectangle (x, y) -\u003e Some (x, y) | _ -\u003e None)\n                    Circle    \u003c!\u003e jreq \"radius\"    (function Circle x -\u003e Some x | _ -\u003e None)\n                    Prism     \u003c!\u003e jreq \"prism\"     (function Prism (x, y, z) -\u003e Some (x, y, z) | _ -\u003e None)\n                ]\n             |\u003e ofObjCodec\n\n```\n\nBut codecs for both types can easily be written with the codec computation expressions\n\n```fsharp\n\ntype Person = { \n    name : string * string\n    age : int option\n    children: Person list } \n    with\n        static member get_Codec () =\n            codec {\n                let! f = jreq \"firstName\" (Some \u003c\u003c fun x -\u003e fst x.name)\n                and! l = jreq \"lastName\"  (Some \u003c\u003c fun x -\u003e snd x.name)\n                and! a = jopt \"age\"       (fun x -\u003e x.age) // Optional fields can use 'jopt'\n                and! c = jreq \"children\"  (fun x -\u003e Some x.children)\n                return { name = (f, l); age = a; children = c } }\n            |\u003e ofObjCodec\n        \n\ntype Shape =\n    | Rectangle of width : float * length : float\n    | Circle of radius : float\n    | Prism of width : float * float * height : float\n    with\n        static member get_Codec () =\n            codec {\n                Rectangle \u003c!\u003e jreq \"rectangle\" (function Rectangle (x, y) -\u003e Some (x, y) | _ -\u003e None)\n                Circle    \u003c!\u003e jreq \"radius\"    (function Circle x -\u003e Some x | _ -\u003e None)\n                Prism     \u003c!\u003e jreq \"prism\"     (function Prism (x, y, z) -\u003e Some (x, y, z) | _ -\u003e None)\n            }\n            |\u003e ofObjCodec\n\n```\n\n\nWhat's happening here is that we're getting a Codec to/from a Json Object (not neccesarily a JsonValue) which Fleece is able to take it and fill the gap by composing it with a codec from JsonObject to/from JsonValue.\n\nWe can also do that by hand, we can manipulate codecs by using functions in the Codec module. Here's an example:\n\n```fsharp\nopen System.Text\nopen Fleece.SystemTextJson.Operators\n\ntype Person = { \n    name : string * string\n    age : int option\n    children: Person list } \n    with\n        static member JsonObjCodec: Codec\u003cPropertyList\u003cFleece.SystemTextJson.Encoding\u003e, Person\u003e = codec {\n            let! f = jreq \"firstName\" (Some \u003c\u003c fun x -\u003e fst x.name)\n            and! l = jreq \"lastName\"  (Some \u003c\u003c fun x -\u003e snd x.name)\n            and! a = jopt \"age\"       (fun x -\u003e x.age) // Optional fields can use 'jopt'\n            and! c = jreq \"children\"  (fun x -\u003e Some x.children)\n            return { name = (f, l); age = a; children = c } }\n\nlet personBytesCodec =\n    Person.JsonObjCodec\n    |\u003e Codec.compose jsonObjToValueCodec    // this is the codec that fills the gap to/from JsonValue\n    |\u003e Codec.compose jsonValueToTextCodec   // this is a codec between JsonValue and JsonText\n    |\u003e Codec.invmap (Encoding.UTF8.GetString: byte [] -\u003e string) Encoding.UTF8.GetBytes    // This is a pair of of isomorphic functions\n\nlet p = { name = \"John\", \"Smith\"; age = Some 42; children = [] }\n\n\nlet bytePerson = Codec.encode personBytesCodec p\n// val bytePerson : byte [] = [|123uy; 34uy; 102uy; 105uy; 114uy; 115uy; ... |]\nlet p' = Codec.decode personBytesCodec bytePerson\n```\n\n### Combinators\n\nSo far we've seen how Fleece is capable of encoding/decoding by deriving automatically a codec from static members in the type.\n\nBut for those cases where we don't have control over the types (extension members won't be taken into account) we can explicitly specify combinators.\n\nTo do so, a set of the available functions exists, ending with the `With` suffix, which accepts a combinator as first parameter:\n\n```fsharp\ntype Color = Red | Blue | White\n\ntype Car = {\n    Id : string\n    Color : Color\n    Kms : int }\n\nlet colorDecoder = function\n    | JString \"red\"   -\u003e Decode.Success Red  \n    | JString \"blue\"  -\u003e Decode.Success Blue \n    | JString \"white\" -\u003e Decode.Success White\n    | JString  x as v -\u003e Decode.Fail.invalidValue v (\"Wrong color: \" + x)\n    | x               -\u003e Decode.Fail.strExpected  x\n\nlet colorEncoder = function\n    | Red   -\u003e JString \"red\"\n    | Blue  -\u003e JString \"blue\"\n    | White -\u003e JString \"white\"\n\nlet colorCodec () = colorDecoder \u003c-\u003e colorEncoder\n    \nlet carCodec () =\n    codec {\n        let! i = jreqWith Codecs.string \"id\"    (fun x -\u003e Some x.Id)\n        and! c = jreqWith colorCodec    \"color\" (fun x -\u003e Some x.Color)\n        and! k = jreqWith Codecs.int    \"kms\"   (fun x -\u003e Some x.Kms)\n        return { Id = i; Color = c; Kms = k }\n    }\n    |\u003e Codec.compose (Codecs.propList Codecs.id)\n\nlet car = { Id = \"xyz\"; Color = Red; Kms = 0 }\n\nlet jsonCar : Fleece.SystemTextJson.Encoding = Codec.encode (carCodec ()) car\n// val jsonCar: SystemTextJson.Encoding = {\"id\":\"xyz\",\"color\":\"red\",\"kms\":0}\n```\n\n### Json Lenses\n\nJson lenses allow to focus on a specific part of the json structure to perform operations like view, write and update.\n\nFor a quick reference have a look at [this test file](https://github.com/fsprojects/Fleece/blob/master/test/Tests/Lenses.fs)\n\n\n## Maintainer(s)\n\n- [@mausch](https://github.com/mausch)\n- [@gusty](https://github.com/gusty)\n- [@wallymathieu](https://github.com/wallymathieu)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffsprojects%2Ffleece","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffsprojects%2Ffleece","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffsprojects%2Ffleece/lists"}