graphql-client icon indicating copy to clipboard operation
graphql-client copied to clipboard

Enum values are converted to uppercase

Open hupo376787 opened this issue 3 years ago • 10 comments

Hi, guys. I noticed that when posting variables, enums are auto-converted to uppercase.

     Variables = new
     {
          qr_type = qrType
    }

    public enum QrEnum
    {
        REGISTER,
        P,
        P_PLUS,
        P_or_P_PLUS
    }

If I pass QrEnum.P_or_P_PLUS, the endpoint receives QrEnum.P_OR_P_PLUS. And returns

"message": "Variable \"$qr_type\" got invalid value \"P_OR_P_PLUS\"; Expected type QrEnum; did you mean P_or_P_PLUS or P_PLUS?",
            "extensions": {
                "category": "graphql"
            },

So how to prevent this case?

hupo376787 avatar Dec 10 '20 08:12 hupo376787

I found that in ConstantCaseEnumConverter.cs

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value == null)
            {
                writer.WriteNull();
            }
            else
            {
                var enumString = ((Enum)value).ToString("G");
                var memberName = value.GetType()
                    .GetMember(enumString, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public)
                    .FirstOrDefault()?.Name;
                if (string.IsNullOrEmpty(memberName))
                {
                    if (!AllowIntegerValues)
                        throw new JsonSerializationException($"Integer value {value} is not allowed.");
                    writer.WriteValue(value);
                }
                else
                {
                    writer.WriteValue(memberName.ToConstantCase());
                }
            }
        }

memberName is converted to upper.

hupo376787 avatar Dec 11 '20 10:12 hupo376787

I also noticed https://github.com/graphql-dotnet/graphql-client/issues/129 and GraphQL's specs.

It seems converting to uppercase is standard?

hupo376787 avatar Dec 11 '20 10:12 hupo376787

I'm also currently struggling with enums. Why does the serializer convert the values per default and does not just use the variable name as the value? Very odd.

In my case I have:

public enum DataType
{
    FooBar,
}

and the client sends FOO_BAR. Also there is no PascalCaseNamingstrategy which I could use on the Newtonsoft-serializer.

How can we fix this?

maaft avatar Dec 11 '20 11:12 maaft

@maaft Currently I downloaded thos repo's source code, and remove the upper method in the code above, then it works again.

hupo376787 avatar Dec 11 '20 11:12 hupo376787

GraphQL uses the FOO_BAR style by default. That's also what the graphql-dotnet library converts your enums to when you create a GraphQL type containing an enum.

You can of course remove the ConstantCaseEnumConverter.cs and implement the intended behaviour yourself.

There is no single solution to the enum (de-)serialization problem, the current implementation works out of the box in when you have a c# enum which is used in both server and client.

The easiest way to get this right is naming enums which are intended to be used with GraphQL according to the recommendations in the GraphQL spec (even if that's not C# standard). Then you won't experience any "conversion problems"..

rose-a avatar Dec 11 '20 12:12 rose-a

I think it's better to give an option, allow to convert uppercase or not.

Since other frameworks like apollo, don't convert by default.

hupo376787 avatar Dec 11 '20 14:12 hupo376787

@rose-a Are you sure that this is defined in the GQL spec? Because I can use (and have used) following schema without problems in every tool from the GQL world (except this client):

enum Foo {
   bar
   BarBar
   Bab_buB
}

I think that it's only a "recommendation" but not a must have per spec (https://spec.graphql.org/June2018/#sec-Enum-Value):

It is recommended that Enum values be “all caps”. Enum values are only used in contexts where the precise enumeration type is known. Therefore it’s not necessary to supply an enumeration type name in the literal.

I think the question is why this client makes assumptions about a "correct" format after all. Just let the user decide and serialize enum values without any reformatting.

maaft avatar Dec 11 '20 17:12 maaft

I'm open to make the current behaviour optional as @hupo376787 suggested. A PR would be most welcome, as I won't get around doing anything about it the next 2 weeks.

If someone wants to take this on, please also consider issues #311 and #312.

rose-a avatar Dec 14 '20 07:12 rose-a

For the history of the internet. Welcome to all people googling this question. EnumerationGraphType has a virtual method ChangeEnumCase that allows you to change the casing of enums.

If you want camelcased enums project wide you can use:

using System;
using GraphQL;
using GraphQL.Types;

namespace MyNs
{
    public class CamelCaseEnumerationGraphType<T> : EnumerationGraphType<T> where T : Enum
    {
        protected override string ChangeEnumCase(string val)
        {
            return val.ToCamelCase();
        }
    }
}

and then inheriting this class instead of EnumerationGraphType

public class MediaTypeEnum : CamelCaseEnumerationGraphType<MediaTypeViewModel>
{
}

Which makes this enum a camelcased one.

luukholleman avatar Dec 22 '21 14:12 luukholleman

Another way to do this here https://github.com/graphql-dotnet/graphql-dotnet/pull/2773

sungam3r avatar Dec 22 '21 16:12 sungam3r