thoth-org / Thoth.Json

Library for working with JSON in a type safe manner, this libs is targeting Fable

Home Page:https://thoth-org.github.io/Thoth.Json/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Suggestion: Expose isomorphic functions for parsing a JsonValue from a string

njlr opened this issue · comments

commented

Sometimes, a service should expect valid JSON but does not care about the JSON schema. In these cases, we need to work with JsonValue but not strongly-typed decoders.

The ability to parse any JSON is already in the library, but (as far as I can tell?) it's not exposed to the user.

Perhaps we could add it to the API?

For .NET:

  let tryParseJsonValue (x : string) : Result<JsonValue, string> =
    try
      use reader = new JsonTextReader(new StringReader(x), DateParseHandling = DateParseHandling.None)

      let json = Newtonsoft.Json.Linq.JValue.ReadFrom reader
      Ok json
    with
      | :? Newtonsoft.Json.JsonReaderException as ex ->
        Error ("Given an invalid JSON: " + ex.Message)

For Fable:

  let tryParseJsonValue (x : string) : Result<JsonValue, string> =
    try
      let json = JS.JSON.parse x
      Ok json
    with
      | ex when Helpers.isSyntaxError ex ->
        Error ("Given an invalid JSON: " + ex.Message)

Then we can inject schema-less JSON into encoders quite naturally:

#r "nuget: Thoth.Json.Net"

open System
open Thoth.Json.Net

let innerJson =
  tryParseJsonValue "{ x: 1 }"
  |>
    function
    | Ok x -> x
    | Error e -> failwith e

let json =
  Encode.object
    [
      "id", Encode.guid (Guid.NewGuid())
      "inner", innerJson
    ]

let s = Encode.toString 2 json

printfn "%A" s

(*

"{
  "id": "bf941f23-db24-4f7d-b5a0-accf8393cd11",
  "inner": {
    "x": 1
  }
}"

*)

You can already do that with the existing API:

Indeed there is the decoder Decode.value which always succeed:

let value _ v = Ok v

Live demo

let json =
    """{ "x": 1 }"""

let innerJson =
    Decode.fromString Decode.value json
    |> function
        | Ok jsonValue -> 
            jsonValue

        | Error errorMessage ->
            failwith errorMessage

let newJson =
  Encode.object
    [
      "id", Encode.guid (System.Guid.NewGuid())
      "inner", innerJson
    ]

let s = Encode.toString 2 newJson

printfn "%A" s
commented

Ah! I hadn't spotted that. Thanks

Ahah no problem :)

TBH it tooks me 20min of writing another answer to think: Hey but don't I have a "discard" decoder already? 🤣