FSharp.Data.GraphQL icon indicating copy to clipboard operation
FSharp.Data.GraphQL copied to clipboard

Remove JsonValue.fs from client and use System.Text.Json

Open xperiandri opened this issue 4 years ago • 10 comments

Description

The JsonValue.fs deserializer deserializes 0 into int while it must deserialize it into the type requested by the schema. Which is float in my case. We can simply use System.Text.Json package version 5 as it is done in https://github.com/fsprojects/SwaggerProvider/tree/net5 with https://github.com/Tarmil/FSharp.SystemTextJson/

Repro steps

  1. Define Float field in GraphQL and return 0.0 from it
  2. Use System.Text.Json as a serializer
  3. You will get int option

Expected behavior

Value is deserialized into the type defined by the schema

Actual behavior

Value is deserialized into the type chosen by JsonValue.fs logic

Related information

1.0.7

xperiandri avatar Apr 03 '21 13:04 xperiandri

There are a few things that the homegrown JSON (and the more widely used Thoth.Json.Net) offers:

  1. Fine-grained control over encoding and decoding without using reflection, annotations or writing "DTO" types:
type Money = 
  {
    Dollars : int
    Cents : int
  }

// JSON representation is:
//     "123.45"

let decode = 
  decoder {
    let! (x : string) = Decode.string

      match x.Split([| '.' |]) with
      | [| dollars; cents |] ->
        let! dollars = 
          match Int32.TryParse(dollars) with
          | true, i -> Decode.succeed i
          | _ -> Decode.fail "Invalid dollars"

        let! cents = 
          match Int32.TryParse(cents) with
          | true, i -> Decode.succeed i
          | _ -> Decode.fail "Invalid cents"

        return { Dollars = dollars; Cents = cents }
      | _ ->
        return! Decode.fail "Expected <dollars>.<cents>"
  }
  1. Ability to visit a JSON structure in a type-safe manner using match
let json = Decode.unsafeFromString "{ \"foo\": 123 }"

match json with
| JsonValue.Object m ->
   match Map.tryFind "foo" m with
   | Some (JsonValue.Integer x) -> x
   | _ -> 0
| _ -> 0
  1. Ability to compare JSON values as values:
let a = Encode.object [ "foo", Encode.int 123 ]
let b = Encode.object [ "foo", Encode.int 123 ]

Assert(a = b)
  1. Support for Fable - we should at some point bring back support for Fable in the client type-provider

Does System.Text.Json offer these?

If not, perhaps they could be built on-top using active patterns?

njlr avatar Oct 09 '22 08:10 njlr

@gusty could you share your opinion?

xperiandri avatar Oct 11 '22 00:10 xperiandri

I agree with @njlr but would add that Fleece offer those same advantages and more (plus it has better performance) only Fable compatibility is still pending at the time of writing this, as no-one added a Fable compatible encoding implementation so far.

gusty avatar Oct 20 '22 20:10 gusty

I agree with @njlr but would add that Fleece offer those same advantages and more (plus it has better performance) only Fable compatibility is still pending at the time of writing this, as no-one added a Fable compatible encoding implementation so far.

I had a glance at Fleece - it looks great!

However, would we need to have an FSharp.Data.GraphQL package for each Fleece back-end?

  • FSharp.Data.GraphQL.NewtonsoftJson
  • FSharp.Data.GraphQL.SystemTextJson
  • ...

njlr avatar Oct 24 '22 15:10 njlr

I expect to use System.Text.Json only

xperiandri avatar Oct 24 '22 17:10 xperiandri

Why specifically System.Text.Json ?

wallymathieu avatar Oct 24 '22 17:10 wallymathieu

Do you have any scenario where you need something else?

xperiandri avatar Oct 24 '22 17:10 xperiandri

I mean, the client shouldn't care about specific Json implementations? I don't know how many times I've had to inject some other Json library or configuration in order to get specific use cases to work. The best would be for it to be pluggable with a default that uses a simple enough interface.

wallymathieu avatar Oct 24 '22 17:10 wallymathieu

I don't have the capacity for that. I sponsor part of this library development from my sallery. So if someone wants to present a solution I ready to discuss. But myself I only interested in System.Text.Json

xperiandri avatar Oct 24 '22 17:10 xperiandri

I don't have the capacity for that. I sponsor part of this library development from my sallery. So if someone wants to present a solution I ready to discuss. But myself I only interested in System.Text.Json

For sure, I know the feeling. There is a limited number of hours I can use to support other open source projects.

Since the library uses explicit knowledge that JsonValue has patterns for String,Null,Record,Array et.c., you could use the same strategy as @gusty has done in Fleece by defining active pattern helpers. I looked at the API surface that is used in the project #400 .

wallymathieu avatar Oct 24 '22 20:10 wallymathieu