federation-hotchocolate icon indicating copy to clipboard operation
federation-hotchocolate copied to clipboard

bug: Unable to input UUID as argument for an ID field

Open anshulshah96 opened this issue 2 years ago • 8 comments

In ArgumentParser.TryGetValue<T>, the casting of all string value node type is done in the following manner:

value = (T)scalarType.ParseLiteral(valueNode)!;

Refer here.

This causes the following error from the subgraph when the input type for an ID field is UUID:

{
  "errors": [
    {
      "message": "Unexpected Execution Error",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "_entities"
      ],
      "extensions": {
        "message": "Unable to cast object of type 'System.String' to type 'System.Guid'.",
        "stackTrace": "   at ApolloGraphQL.HotChocolate.Federation.Helpers.ArgumentParser.TryGetValue[T](IValueNode valueNode, IType type, String[] path, Int32 i, T& value)\n   at ApolloGraphQL.HotChocolate.Federation.Helpers.ArgumentParser.TryGetValue[T](IValueNode valueNode, IType type, String[] path, Int32 i, T& value)\n   at ApolloGraphQL.HotChocolate.Federation.Helpers.ArgumentParser.GetValue[T](IValueNode valueNode, IType type, String[] path)\n   at lambda_method15(Closure, IResolverContext)\n   at ApolloGraphQL.HotChocolate.Federation.Helpers.EntitiesResolver.ResolveAsync(ISchema schema, IReadOnlyList`1 representations, IResolverContext context)\n   at HotChocolate.Types.ResolveObjectFieldDescriptorExtensions.<>c__DisplayClass3_0`1.<<Resolve>b__0>d.MoveNext()\n--- End of stack trace from previous location ---\n   at HotChocolate.Types.Helpers.FieldMiddlewareCompiler.<>c__DisplayClass9_0.<<CreateResolverMiddleware>b__0>d.MoveNext()\n--- End of stack trace from previous location ---\n   at HotChocolate.Execution.Processing.Tasks.ResolverTask.ExecuteResolverPipelineAsync(CancellationToken cancellationToken)\n   at HotChocolate.Execution.Processing.Tasks.ResolverTask.TryExecuteAsync(CancellationToken cancellationToken)"
      }
    }
  ]
}

anshulshah96 avatar Nov 01 '23 13:11 anshulshah96

Hello 👋 UUID is a custom scalar so the logic would have to account for mapping custom scalar (Any) to a custom scalar (UUID). I am unsure whether we will be able to support it.

As a workaround you will need to manually parse it

[ReferenceResolver]
public static Foo GetByFooBar(
    [LocalState] ObjectValueNode data
    Data repository)
{
    // TODO implement logic here by manually reading values from local state data
}

dariuszkuc avatar Nov 01 '23 14:11 dariuszkuc

@dariuszkuc Is this intentional, because this is handled transparently in the previous federation implementation?

LavaToaster avatar Nov 01 '23 16:11 LavaToaster

Did it actually work? The code is pretty much the same this vs that.

Looks like the only difference is around handling non-null types - I only applied the check for object types as it seemed working fine for other types (looks like their fix made it to 13.6.0).

dariuszkuc avatar Nov 01 '23 17:11 dariuszkuc

The underlying issue is with the IdType. Fields using Guid by itself work fine.

When we invoke the TryGetValue it attempts to fetch the IdType which serializes as a string and it doesn't know that the underlying type is actually Guid (i.e. we don't know that IdType should be wrapping UuidType). So the logic there would somehow need to know to parse the string value (ID) and then try to parse it again to Guid. You would encounter the same problem with any other custom scalar.

Since ID scalar is serialized to String we can also do following workaround

[ReferenceResolver]
public static Foo GetByGuid(
    string id
    Data repository)
{
    var guid = Guid.Parse(id);
    // TODO implement logic here by manually reading values from local state data
}

I am unsure whether HotChocolate allows you to provide custom biding for existing scalar types - IF it does support it then maybe you could provide your own ParseLiteral logic to also support GuidType.

dariuszkuc avatar Nov 01 '23 18:11 dariuszkuc

related: #19 and #20

dariuszkuc avatar Nov 01 '23 19:11 dariuszkuc

Ah ok that makes sense, we weren't using ID types before so that would explain why we didn't see it.

LavaToaster avatar Nov 02 '23 13:11 LavaToaster

I tried the above suggestion of using string in the ReferenceResolvers. But I still run into the following error:

{
  "data": {},
  "errors": [
    {
      "message": "invalid type for variable: '<variable1>'",
      "extensions": {
        "name": "<variable1>",
        "code": "VALIDATION_INVALID_TYPE_VARIABLE"
      }
    },
    {
      "message": "invalid type for variable: '<variable2>'",
      "extensions": {
        "name": "<variable2>",
        "code": "VALIDATION_INVALID_TYPE_VARIABLE"
      }
    }
  ]
}

anshulshah96 avatar Nov 02 '23 16:11 anshulshah96

Please provide a link to a repository that reproduces the issue. Otherwise it is very hard to determine what is the underlying issue.

dariuszkuc avatar Nov 02 '23 16:11 dariuszkuc