I am new to GraphQL and I'm currently trying to build an api for a existing library.
There I have Tags which have an unique alias, a value which can be of different types and some properties.
To take care of the different value types, I have defined an interface containing alias and properties as well as 4 implementations with a differently typed value field.
The GraphQL schema is as follows:
schema {
query: Query
mutation: Mutation
}
type Query {
allTags: [Tag!]
tags(aliases: [ID!]!): [Tag]
tag(alias: ID!): Tag
}
interface Tag {
alias: ID! @isUnique
properties: [TagProperty]
}
type StringTag implements Tag {
alias: ID! @isUnique
properties: [TagProperty]
value: String
}
type IntegerTag implements Tag {
alias: ID! @isUnique
properties: [TagProperty]
value: Int
}
type FloatTag implements Tag {
alias: ID! @isUnique
properties: [TagProperty]
value: Float
}
type BooleanTag implements Tag {
alias: ID! @isUnique
properties: [TagProperty]
value: Boolean
}
type TagProperty {
name: String!
value: String!
}
In the interface implementation in C#, I want to use ResolveType as suggested in the graphql-dotnet getting started docs.
The code for the interface implementation:
public TagInterface(
BooleanTag booleanTag,
IntegerTag integerTag,
FloatTag floatTag,
StringTag stringTag)
{
Name = "Tag";
Description = "A resource which points to a value";
Field<IdGraphType>(
"alias",
"the unique alias of the tag"
);
Field<ListGraphType<TagPropertyType>>(
"properties",
"the properties of a tag defined in the config XML"
);
ResolveType = obj =>
{
if (obj is HtTag)
{
switch ((obj as HtTag).DataType) {
case EDataType.Bool:
return booleanTag;
case EDataType.Byte:
case EDataType.Sbyte:
case EDataType.Short:
case EDataType.Ushort:
case EDataType.Int:
case EDataType.Uint:
case EDataType.Long:
case EDataType.Ulong:
return integerTag;
case EDataType.Double:
case EDataType.Float:
case EDataType.Decimal:
return floatTag;
default:
return stringTag;
}
}
throw new ArgumentOutOfRangeException($"Could not resolve graph type for {obj.GetType().Name}");
};
}
}
When I run the following query
query {
tags(aliases:["TagID_S1A02_IN","TagID_S1A03_IN"]) {
__typename
alias
... on StringTag {
value
}
... on IntegerTag {
value
}
... on BooleanTag {
value
}
... on FloatTag {
value
}
}
}
I get the following error:
{
"errors": [
{
"message": "Für dieses Objekt wurde kein parameterloser Konstruktor definiert."
}
]
}
This seems to be because of the 4 constructor parameters in the interface definition (which is according to the example in the docs). If I remove them and return new StringTag()
etc. in the ResolveType implementation, I get the correct number of results, but without content:
{
"data": {
"tags": [
{
"__typename": "StringTag",
"alias": null,
"value": null
},
{
"__typename": "StringTag",
"alias": null,
"value": null
}
]
}
}
Can anyone please point out to me what I'm doing wrong here?
Update
I got it working by using the parameterless constructor and returning the resolved object like this:
ResolveType = obj =>
{
if (obj is HtTag)
{
switch ((obj as HtTag).DataType) {
case EDataType.Bool:
return (from t in PossibleTypes where t is BooleanTag select t).First();
case EDataType.Byte:
case EDataType.Sbyte:
case EDataType.Short:
case EDataType.Ushort:
case EDataType.Int:
case EDataType.Uint:
case EDataType.Long:
case EDataType.Ulong:
return (from t in PossibleTypes where t is IntegerTag select t).First();
case EDataType.Double:
case EDataType.Float:
case EDataType.Decimal:
return (from t in PossibleTypes where t is FloatTag select t).First();
default:
return (from t in PossibleTypes where t is StringTag select t).First();
}
}
throw new ArgumentOutOfRangeException($"Could not resolve graph type for {obj.GetType().Name}");
};
Is this the way it is supposed to be used?