Zaid-Ajaj / Snowflaqe

A dotnet CLI to generate type-safe GraphQL clients for F# and Fable with automatic deserialization, static query verification and type checking
MIT License
154 stars 25 forks source link

Problems when using generated input types from Hasura backend #76

Closed gmlion closed 1 year ago

gmlion commented 1 year ago

I'm facing several issues trying to execute mutation on a F# backend towards Hasura, sending instances of the generated input types, such as

type Example_insert_input =
    { AnotherType: Option<AnotherType_obj_rel_insert_input>
      anotherType: Option<string>
      id: Option<string>
    }

When using default serializer Newtonsoft.Json, it throws an exception A member with the name 'anotherType' already exists on 'KrevS2Graphql.SkillModelVersion_insert_input'. Use the JsonPropertyAttribute to specify another name.

When using System.Text.Json ("system") serializer, Hasura return an error due to a mismatch between discriminated union names. Upon further investigation, this is caused by the fact that the CompiledName attributed is not respected. Next step is to set "normalizeEnumCases" to false. This solves the previous issues, but another error is given back by Hasura: expected an object for type 'Example_bool_exp', but found null. So, it looks like properties set to None on the various types generated by Snowflaqe are not serialized in a way that Hasura correctly receive them - I think those properties should be excluded, instead of defined with a null value.

gmlion commented 1 year ago

I think I found the root problem for the last stopper https://github.com/Tarmil/FSharp.SystemTextJson/issues/140

Zaid-Ajaj commented 1 year ago

Hi there @gmlion thanks for filing the issue! I am able to reproduce it locally with a console app as follows:

open Newtonsoft.Json
open Fable.Remoting.Json

type Example_insert_input =
    { AnotherType: Option<int>
      anotherType: Option<string>
      id: Option<string>
    }

let fableJsonConverter = FableJsonConverter() :> JsonConverter

let input = {
    AnotherType = Some 1
    anotherType = Some "test"
    id = Some "test"
}

let settings = JsonSerializerSettings(DateParseHandling=DateParseHandling.None, Converters = [| fableJsonConverter |])
let inputJson = JsonConvert.SerializeObject(input, settings)

printfn $"{inputJson}"

This is an issue in Fable.Remoting.Json, the specialized JSON serializer used in generated clients. It looks like we don't handle records in any special way and default to whatever Newtonsoft.Json does. Being unable to serialize this trivial type is not ideal. I'll have a look at it πŸ˜„

Zaid-Ajaj commented 1 year ago

Fixed as of Snowflaqe v1.41 πŸš€ which should work using the default (newtonsoft) serializer. Please take it for a spin and let me know how it goes 😁

gmlion commented 1 year ago

Hey, thanks for the fix. The first issue with Newtonsoft is indeed fixed with the last update, but now I still have problem number 3, which it turns out does not depend on the specific serializer used.

All the properties set to None are serialized as null values, so using the generated types with Hasura does not work. This includes both the properties of the graphql types which should be optional and the other properties of the DTO, such as on_conflict, constraint, update_columns, where.

An example error from Hasura is expected an object for type 'ExampleType_bool_exp', but found null

Zaid-Ajaj commented 1 year ago

@gmlion In GraphQL, as far as I know, setting null for optional fields is fine and accepted. So I am not sure why hasura is not happy with nulls. However, I am think we can fix it on our side of things. It could be another option in JsonSerializerSettings. I will have a look

Zaid-Ajaj commented 1 year ago

but now I still have problem number 3, which it turns out does not depend on the specific serializer used.

@gmlion Should be resolved as of Snowflaqe v1.42 πŸš€ please give it a try and let me know how it goes πŸ˜„

gmlion commented 1 year ago

Hi, the situation is partially fixed. Now properties of the original type are no longer serialized as null, but others still are (on_conflict, where...)

Zaid-Ajaj commented 1 year ago

@gmlion did you use version 1.42 or v1.43? because latest v1.43 should solve this problem entirely.

gmlion commented 1 year ago

It is now working, thank you very much!

Zaid-Ajaj commented 1 year ago

@gmlion thanks for confirming πŸ™ glad to hear it is working for you