Currently, Hasura creates a new scalar type called uuid for UUID keys. Because it's a non-standard type, using it with clients usually means jumping through some hoops to treat the value as a string. But, that's really all the standard ID type does anyway, as far as I know. I think if this type were remapped in the schema, it'd improve the ergonomics of working with a Hasura-based GraphQL server.
Is there anything I can do to help usher this one along? It's a major pain point using Hasura with a ReasonML-based client.
@nirvdrum (I think we were chatting on the community call a few minutes ago?)
Do you have any ideas on the best way of doing this?
Maybe an optional field in the metadata / in the console to mark any primary key column as an ID type? Considering an ID type is really just a name and a string serialization any postgres PK should work.
I inquired about this on today's community call and it was asked that I provide more data on what I think the solution could look like.
According to the latest published version of the GraphQL Spec:
The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, it is not intended to be human‐readable. While it is often numeric, it should always serialize as a String.
Result Coercion
GraphQL is agnostic to ID format, and serializes to string to ensure consistency across many formats ID could represent, from small auto‐increment numbers, to large 128‐bit random numbers, to base64 encoded values, or string values of a format like GUID.
GraphQL servers should coerce as appropriate given the ID formats they expect. When coercion is not possible they must raise a field error.
Input Coercion
When expected as an input type, any string (such as "4") or integer (such as 4) input value should be coerced to ID as appropriate for the ID formats a given GraphQL server expects. Any other input value, including float input values (such as 4.0), must raise a query error indicating an incorrect type.
So, the spec not only permits UUIDs to be represented as the ID type, but it explicitly provides this use case as an example. As far as I know, the only sensible way to work with the custom scalar type uuid with Hasura is to treat it as a String coming in and going out. Thus, I think you can and should change the generated schema to return UUID PKs as the GraphQL ID type. It probably makes sense to do the same for FKs, but that may be trickier to work out. I don't know what Hasura does for int FKs today, but it should probably map the same way. For arbitrary UUID columns, the custom scalar likely still makes sense -- I think that boils down to interpretation of what the spec means when it says "represents a unique identifier". UUIDs are unique identifiers by definition, but they may not be unique in the backing database if stored in a non-unique column.
Since I'm advocating for a change in the generated schema, it could potentially break things for people. Maybe it'd make sense to have an option to ease migration. But, I truly believe mapping as ID by default is the best way to go.
I think a Hasura metadata/console option that makes it easy to mark any UUID or Text column to an ID GraphQL type would work absolutely fine.
This should work well with the auto-generated resolvers and all the filter/sort options as well because Hasura can internally map the ID type back to UUID and text and all the operators will stay the same.
@0x777 @tirumaraiselvan Any thoughts? Any more input we need from @nirvdrum before we can turn this into a small RFC?
@nirvdrum Just for context for other folks on the team and anyone who comes across this issue, what kinds of things do you need to do on the reaonml client to make the UUID type work as a string type?
@coco98 Thanks for the follow-up. An option in the console would be fine, too. I'd suggest maybe it should default to "on" in new tables if using the UUID PK "frequently used column" helper. I'd imagine this is something that'll come up as you consider Relay compatibility as well.
ReasonML is probably a niche use case, but I appreciate you considering it. Since ReasonML is statically typed, every GraphQL response needs to be decoded to some defined type. Since uuid is mapped as a custom scalar, graphql_ppx (a popular low-level library for working with GraphQL) doesn't know what to do with it, so it treats it as JSON object (Js.Json.t). If you're just recording the value and using it elsewhere for queries, there's no problem -- the key is already in the required type. But, anywhere where you might want to store the ID as a string (e.g., React component key), you have to do an awkward conversion to decode the JSON object:
let id = obj => {
obj##id |> Js.Json.decodeString |> Belt.Option.getExn;
};
Likewise, if you have a string value somewhere that you want to use as a query variable, you need to encode it to a JSON object:
let makeId = id => {
Js.Json.string(id);
};
It doesn't seem like much, but it's a mess of code needed for many interactions with every table. There are some ways this could be made nicer in ReasonML, but that's the issue broadly. I have a feature request open to provide global serializers for custom scalars to help ease this from the graphql_ppx side. But, I'd rather have my PKs mapped as GraphQL ID.
Thanks for the context @nirvdrum. This is helpful! :)
@coco98 No problem. Is there anything else I can do to help move this one along? It's made working with Hasura much uglier than I'd like. I was hoping this change was reasonably small enough to make its way into the 1.2.0 release.
Because of this issue, generating Typescript types for Relay (using relay-compiler) will assign the "unknown" type to UUIDs. It's a problematic issue that should not be there in the first place. Any update on this ?
Creating a Remote Relationships with Sanity.io is not possible because of this.
Is this issue on the roadmap? It has turned into a blocker for us, as we can't use Remote Schemas as-is, since they depend on IDs that are shared across systems (uuids in Hasura).
@jacdx Yes, this will be picked up very soon.
@tirumaraiselvan Any updates on that issue? We're also unable to use Hasura with remote schemas in the meantime.
@flobaader We just released v1.3.4-beta1 which will allow joining String, Int or UUID types with ID type.
@tirumaraiselvan Thank you very much for the quick response! I just tried the new beta and it works perfectly fine. You made my day!
@philschonholzer You can now use Hasura with Sanity.io
Woohoo!
On Wed, Nov 25, 2020 at 6:23 AM Florian Baader notifications@github.com
wrote:
@tirumaraiselvan https://github.com/tirumaraiselvan Thank you very much
for the quick response! I just tried the new beta and it works perfectly
fine. You made my day!
@philschonholzer https://github.com/philschonholzer You can now use
Hasura with Sanity.io—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/hasura/graphql-engine/issues/3578#issuecomment-733737138,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AARM2IWJHSGWGY34ZMPZZQDSRUHOLANCNFSM4J57W2YA
.
Just tried v1.3.4-beta.1 && beta.2 without success. Silently failing remote join on ID type in remote to UUID type in hasura. Extra bit of info is I'm trying to do it on a view.
Best way to diagnose?
Ok tried 3 times and 3rd time worked. 🎉 Unsure why. v1.3.4-beta.1
Most helpful comment
@jacdx Yes, this will be picked up very soon.