I have a schema where the json can have a list of Int and Strings as values. I am wondering how to define a type of resolver for my scenario.
type Total {
key: String
values: [Object]
}
type Query {
filter (key : String!) : Total
}
There is no concept of general object (as Object in Java) in GraphQL. In fact, the defined type are the following (as described here):
You could define a new scalar but it means that you will have to define yourself how it would be serialized/deserialized and validated. It add way more complexity for not much value. Moreover, I feel that the strong typing of Graphql is completely lost with this specific type.
I think your best bet is to use the Interfaces. With an interface and using wrapper types, you are then able to model this general object that you are talking about, and would help you write a schema as follow:
interface MyInterface {
// must have a field at least (cannot be empty)
id: ID!
}
type MyInt implements MyInteface {
// Inherited by MyInterface
id: ID!
myIntValue: Int
}
type MyString implements MyInteface {
// Inherited by MyInterface
id: ID!
myStringValue: String
}
type Total {
key : String
values: [MyInterface]
}
type Query {
filter(key: String!) : Total
}
Careful: please note that the interface isn't allowed to be empty (no fields). For that purpose, I added an ID field that is by implementation randomly generated.
With such a schema, we are able to perform a query like the following:
filter("someFilter") {
key
values {
... on MyString {
myStringValue
}
... on MyInt {
myIntValue
}
}
}
For that to work you would need to define a TypeResolver, as follow:
private class MyInterfaceTypeResolver implements TypeResolver {
@Override
public GraphQLObjectType getType(TypeResolutionEnvironment env) {
Object obj = env.getObject();
if (obj instanceOf MyInt) {
env.getSchema().getObjectType("MyInt");
} else if (obj instanceOf MyString) {
env.getSchema().getObjectType("MyString");
} else {
return null;
}
}
}
with the following Java types definition:
abstract class MyInterface {
private String id;
public MyInterface() {
// Generated just to avoid empty graphql interface
id = UUID.randomUUID().toString();
}
public String getId() {
return id;
}
}
class MyInt extends MyInterface {
private Integer myIntValue;
public MyInt(Integer myInt) {
super();
this.myIntValue= myInt;
}
public Integer getMyIntValue() {
return myInt;
}
}
class MyString extends MyInterface {
private String myStringValue;
public MyString (String myString) {
super();
this.myStringValue= myString;
}
public String getMyStringValue() {
return myStringValue;
}
}
Assuming that you want to represent the following Json {"key": "myKey", "values":[12,"String1", 1, "String2"]}
, given our previous model and query, it would be represented like this:
{
"data": {
"filter": {
"key": "myKey",
"values" : [
{
"myIntValue": 12
},
{
"myStringValue": "String1"
},
{
"myIntValue": 1
},
{
"myStringValue": "String2"
}
]
}
}
}
Lastly, you could just have multiple attributs, one for each type, such as follow:
type Total {
key : String
valuesInt: [Int]
valuesString: [String]
}
type Query {
filter(key: String!) : Total
}