graphql-platform: Custom scalar for JObject is not parsed correctly

Describe the bug

I want to write a custom scalar for the JSON object of any shape (I know I know about strong typing and GraphQL but…) and when I do this hotchocolate incorrectly parses the input object.

All works fine if you use this scalar type as mutation argument but doesn’t work when it’s a field of InputObjectType.

To Reproduce Steps to reproduce the behavior:

  1. Create custom scalar for JSON object
Scalar Implementation
public class JsonScalarType : HotChocolate.Types.ScalarType
    {
        public JsonScalarType() : base("JsonScalar")
        {
        }

        protected JsonScalarType(string name) : base(name)
        {
        }

        public override Type ClrType => typeof(object);

        public override bool IsInstanceOfType(IValueNode literal)
        {
            if (literal == null) throw new ArgumentNullException(nameof(literal));
            return literal is NullValueNode || literal is ObjectValueNode;
        }

        public override object ParseLiteral(IValueNode literal)
        {
            if (literal is NullValueNode) // NullValueNode is present after TryDeserialize call
                return null;
            throw new NotImplementedException();
        }

        public override IValueNode ParseValue(object value)
        {
            throw new NotImplementedException();
        }

        public override object Serialize(object value)
        {
            if (!(value is JObject jo))
                throw new ArgumentException(nameof(value));
            return jo;
        }

        public override bool TryDeserialize(object serialized, out object value)
        {
            if (serialized is Dictionary<string, object>)
            {
                value = JObject.FromObject(serialized);
                return true;
            }

            if (serialized is JObject)
            {
                value = serialized;
                return true;
            }

            value = null;
            return false;
        }
    }
2. Register it as a field inside input object type and add to mutation
Input Object Type
public class ComplexInput
{
    [GraphQLType(typeof(JsonScalarType))]
    public JObject Inner { get; set; }
}
3. Register `ComplexInput` in mutation
Mutation
public class Mutation {

    public string ProcessJsonScalar([GraphQLType(typeof(JsonScalarType))] JObject input)
    {
        return $"ok: {input}";
    }

    public string ProcessComplexJsonScalar(ComplexInput input)
    {
        return $"ok: {input.Inner}";
    }
}
  1. send mutation
mutation send($input: ComplexInput) {
  processComplexJsonScalar(input: $input) 
}

Variables:

{
  "input": {
    "inner": {
        "someCustomProp": 1,
        "someCustomProp2": 2
    }
  }
}

Expected behavior Custom scalar is correctly parsed into JObject

Actual behavior: null is returned

Additional context .NET Core 2.2 hotchocolate version 11.0.0-preview.2

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 21 (14 by maintainers)

Most upvoted comments

I have talked to Ivan about this (the graphql-js maintainer) and it is not forbidding to do that. I had interpreted some sections of the spec differently but I was wrong here.

We will create the new AnyType so that it really can be anything (object, int, float, string, bool).

I will describe the AnyType in more detail in a separate issue that I will link to this issue.

We will put this in 10.1.0 so expect it in the next two weeks.

So, we will build in a proper any type with 10.1