graphql-client
graphql-client copied to clipboard
Enum values are converted to uppercase
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?
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.
I also noticed https://github.com/graphql-dotnet/graphql-client/issues/129 and GraphQL's specs.
It seems converting to uppercase is standard?
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 Currently I downloaded thos repo's source code, and remove the upper method in the code above, then it works again.
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"..
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.
@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.
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.
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.
Another way to do this here https://github.com/graphql-dotnet/graphql-dotnet/pull/2773