{"id":17982354,"url":"https://github.com/pedrobslisboa/universal-json","last_synced_at":"2025-10-22T02:58:59.326Z","repository":{"id":239594945,"uuid":"798732537","full_name":"pedrobslisboa/universal-json","owner":"pedrobslisboa","description":"Universal JSON handlers for natively and js apps","archived":false,"fork":false,"pushed_at":"2024-05-17T14:16:39.000Z","size":75,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T19:32:10.731Z","etag":null,"topics":["json","ocaml","reasonml","universal"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pedrobslisboa.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-10T10:59:17.000Z","updated_at":"2024-10-10T15:26:42.000Z","dependencies_parsed_at":"2024-10-29T18:35:46.173Z","dependency_job_id":null,"html_url":"https://github.com/pedrobslisboa/universal-json","commit_stats":null,"previous_names":["pedrobslisboa/universal-json"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pedrobslisboa/universal-json","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrobslisboa%2Funiversal-json","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrobslisboa%2Funiversal-json/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrobslisboa%2Funiversal-json/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrobslisboa%2Funiversal-json/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pedrobslisboa","download_url":"https://codeload.github.com/pedrobslisboa/universal-json/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrobslisboa%2Funiversal-json/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270781196,"owners_count":24643804,"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","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["json","ocaml","reasonml","universal"],"created_at":"2024-10-29T18:14:03.711Z","updated_at":"2025-10-22T02:58:59.257Z","avatar_url":"https://github.com/pedrobslisboa.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Universal Ocaml Json encode/decode\n\nUniversal Json for both natively Ocaml/Reason and Js apps.\n\nThis project was inspired by [melange-json](https://github.com/melange-community/melange-json) and [YoJson](https://github.com/ocaml-community/yojson)\n\nThis library can be used on both melange an native ocaml without external contract dependency.\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n    - [Encode](#encode)\n        - [API](#api)\n        - [Examples](#examples)\n    - [Decode](#decode)\n        - [API](#api-1)\n        - [Examples](#examples-1)\n    - [Interop](#interop)\n        - [Js.Json (Client only)](#jsjson-client-only)\n        - [Yojson (Native only)](#yojson-native-only)\n\n## Installation\n\nThere is no opam version yet, so you can install it by pinning the repository:\n```sh\nopam pin add universal-json.dev \"git+https://github.com/pedrobslisboa/universal-json#main\"\n```\n\n#### For client dune config add\n\n```dune\n (libraries universal-json.js)\n```\n\n#### For native dune config add\n\n```dune\n (libraries universal-json.native)\n```\n\n\n## Usage\n\nThis library doesn't use the native Json parsing and stringfy libraries, it has its own implementation, the code is strongly typed and can build the json endode without calling the Json encode function.\n\n### Json\n\n#### API\n\n```ocaml\ntype t =\n  | Null\n  | Bool of bool\n  | Int of int\n  | Float of float\n  | String of string\n  | List of t list\n  | Assoc of (string * t) list\n\nval parse : string -\u003e t option\n(* returns None if the input is not a valid JSON string *)\nval parseOrRaise : string -\u003e t\n(* raises Json.ParseError with the error message if the input is not a valid JSON string *)\nval stringify : t -\u003e string\n```\n\n### Encode\n\n#### API\n\n```ocaml\nmodule Encode : sig\n    val string : string -\u003e Json.t\n    val int : int -\u003e Json.t\n    val float : float -\u003e Json.t\n    val bool : bool -\u003e Json.t\n    val null : Json.t\n    val list : Json.t list -\u003e Json.t\n    val assoc : (string * Json.t) list -\u003e Json.t\n    val object_ : (string * Json.t) list -\u003e Json.t\nend\n```\n\n#### Examples\n\nYou can easily build a json string by using the Json.Encode module:\n\n```ocaml\n(* val json : Json.t *)\nlet json = `Assoc [\n    (\"name\", `String \"John\");\n    (\"age\", `Int 30);\n    (\"grades\", `List [`Int 90; `Int 80; `Int 70]);\n    (\"address\", `Assoc [\n        (\"street\", `String \"123 Main St\");\n        (\"city\", `String \"Sometown\");\n        (\"state\", `String \"Sp\");\n        (\"zip\", `String \"12345\");\n    ]);\n]\n\n(* is the same of *)\n\nlet json = Json.Encode.(\n    assoc [\n        \"name\", string \"John\";\n        \"age\", int 30;\n        \"grades\", list [int 90; int 80; int 70];\n        \"address\", object_ [\n            \"street\", string \"123 Main St\";\n            \"city\", string \"Sometown\";\n            \"state\", string \"Sp\";\n            \"zip\", string \"12345\";\n        ];\n    ]\n)\n```\n\n### Decode\n\n#### API\n\n```ocaml\nmodule Decode : sig\n    val string : Json.t -\u003e string\n    val int : Json.t -\u003e int\n    val float : Json.t -\u003e float\n    val bool : Json.t -\u003e bool\n    val list : ('a -\u003e 'b) -\u003e Json.t -\u003e 'b list\n    val assoc : ('a -\u003e Json.t) -\u003e (string * 'a) list -\u003e Json.t\n    val at : string list -\u003e ('a -\u003e Json.t) -\u003e 'a -\u003e 'b\n    val field : string -\u003e ('a -\u003e Json.t) -\u003e 'a -\u003e 'b\n    val one_of : (Json.t -\u003e 'a) list -\u003e Json.t -\u003e 'a\n    val nullable : ('a -\u003e 'b) -\u003e Json.t -\u003e 'b option\n    val either : (Json_Util.t -\u003e 'a) -\u003e (Json_Util.t -\u003e 'a) -\u003e Json_Util.t -\u003e 'a\n    val map : ('a -\u003e 'b) -\u003e ('c -\u003e 'a) -\u003e 'c -\u003e 'b\n    val and_then : ('a -\u003e 'b -\u003e 'c) -\u003e ('b -\u003e 'a) -\u003e 'b -\u003e 'c\n    val with_default : 'a -\u003e ('b -\u003e 'a) -\u003e 'b -\u003e 'a\n'a\nend\n```\n\n#### Examples\n\nTo decode a json string\n\n```ocaml\ntype person = {\n    name: string;\n    age: int;\n    grades: int list;\n    address: {\n        street: string;\n        city: string;\n        state: string;\n        zip: string;\n    };\n}\n\n(* val json : Json.t *)\nlet json = Json.parseOrRaise {|{\"name\": \"John\", \"age\": 30, \"grades\": [90, 80, 70], \"address\": {\"street\": \"123 Main St\", \"city\": \"Sometown\", \"state\": \"Sp\", \"zip\": \"12345\"}}|}\n\n(* val decode_person : Json.t -\u003e person *)\nlet decode_person json =\n    let open Json.Decode in\n    let name = field \"name\" string json in\n    let age = field \"age\" int json in\n    let grades = field \"grades\" (list int) json in\n    let address = field \"address\" (fun json -\u003e\n        let open Json.Decode in\n        let street = at [\"address\", \"street\"] string json in\n        let city =  at [\"address\", \"city\"] string json in\n        let state =  at [\"address\", \"state\"] string json in\n        let zip =  at [\"address\", \"zip\"] string json in\n        {street; city; state; zip}\n    ) json in\n\n    {name; age; grades; address}\n```\n\nYou can also build your decoded hashtable by using assoc and then set it to any hashtable tool:\n\nto Hashtbl (Universal)\n\n```ocaml\n(* val json : Json.t *)\nlet json = Json.parseOrRaise {|{\"name\": \"John\", \"age\": 30, \"grades\": [90, 80, 70], \"address\": {\"street\": \"123 Main St\", \"city\": \"Sometown\", \"state\": \"Sp\", \"zip\": \"12345\"}}|}\n\n(* val assoc : Json.t -\u003e (string, 'a) list *)\n(* val decode_person : Json.t -\u003e (string, string) Hashtbl.t *)\nlet decode_person json =\n  let open Decode in\n  let person = assoc string json in\n  let target = Hashtbl.create @@ List.length person in\n  List.fold_left\n    (fun acc (key, value) -\u003e\n      Hashtbl.replace acc key value;\n      target)\n    target person\n```\n\nto Js.Dict (Universal with server-reason-react.js)\n\n```ocaml\n(* val json : Json.t *)\nlet json = Json.parseOrRaise {|{\"name\": \"John\", \"age\": 30, \"grades\": [90, 80, 70], \"address\": {\"street\": \"123 Main St\", \"city\": \"Sometown\", \"state\": \"Sp\", \"zip\": \"12345\"}}|}\n\n(* val decode_person : Json.t -\u003e string Js.Dict.t *)\nlet decode_person json =\n  let open Decode in\n  let person = assoc string json in\n  Js.Dict.fromList person\n```\n\n### Interop\n\n\nThe code is prepared to convert safely from Js.Json to Json and vice versa, and also from Yojson to Json and vice versa:\n\n#### Js.Json (Client only)\n\n```ocaml\n(* val json : Json.t *)\nlet json = Json.parseOrRaise {|{\"name\": \"John\", \"age\": 30}|}\n\n(* val to_js_json : Json.t -\u003e Js.Json.t *)\n(* val js_json : Js.Json.t *)\nlet js_json = Json.Client.to_js_json json\n\n(* val of_js_json : Js.Json.t -\u003e Json.t *)\n(* val json : Json.t *)\nlet json = Json.Client.of_js_json js_json\n```\n\n#### Yojson (Native only)\n\n```ocaml\n(* val json : Json.t *)\nlet json = Json.parseOrRaise {|{\"name\": \"John\", \"age\": 30}|}\n\n(* val to_yojson : Json.t -\u003e Yojson.Safe.json *)\n(* val yojson : Yojson.Safe.json *)\nlet yojson = Json.Native.to_yojson json\n\n(* val of_yojson : Yojson.Safe.json -\u003e Json.t *)\n(* val json : Json.t *)\nlet json = Json.Native.of_yojson yojson\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrobslisboa%2Funiversal-json","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpedrobslisboa%2Funiversal-json","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrobslisboa%2Funiversal-json/lists"}