Reputation: 12639
I'm trying to figure out how to access the args
field of retrieveRowsWithoutLocations
. However, I'm not even sure what goes into the value
parameter in the resolveType
function of UnionType.
I'm looking at the documentation https://graphql.org/graphql-js/type/#graphqluniontype but it's quite brief and doesn't go into detail where that information is picked up from. I've tried looking at other sources but they aren't graphql-js.
What I'm trying to do is access args.type
and check its value, which then allows the union to decide which type it should return.
let rows_union =
new graphql.GraphQLUnionType({
name:
"rows_union",
types:
[
many_item,
many_list,
many_display_list,
],
resolveType(value)
{
switch(value)
{
case "item":
return many_item
case "list":
return many_list
case "display_list":
return many_display_list
}
}
})
// Define the Query type
var query =
new graphql.GraphQLObjectType({
name: "Query",
fields:
{
retrieveRowsWithoutLocations:
{
type:
rows_union,
args:
{
_id:
{
type:
nonNullId()
},
page:
{
type:
nonNullInt()
},
page_length:
{
type:
nonNullInt()
},
type:
{
type:
nonNullString()
},
},
async resolve ()
{
}
},
}
})
let many_type =
new graphql.GraphQLObjectType({
name: "many_"+name,
fields: {
results: {
type: graphql.GraphQLList(type)
},
total: {
type: graphql.GraphQLNonNull(graphql.GraphQLInt)
},
}
})
type
is another ObjectType
Upvotes: 1
Views: 424
Reputation: 84687
You cannot directly access any resolver parameters inside resolveType
(or isTypeOf
). When a field is resolved, the resolver returns some value, or a Promise that will resolve to that value. In the case of a field that returns an output type, interface or union, this value should be a JavaScript object. It's this value that is then passed to resolveType
, which is used to determine what type is actually being returned in the response at runtime.
Given a schema like
union Animal = Bird | Fish
type Bird {
numberOfWings: Int
}
type Fish {
numberOfFins: Int
}
type Query {
animal: Animal
}
you can image that the resolver for the animal
field returns JavaScript objects like { numberOfWings: 2 }
{ numberOfFins: 4 }
. Here, we could utilize a simple heuristic to determine the type:
resolveType: (value) => {
if (value.numberOfWings !== undefined) {
return 'Bird'
} else if (value.numberOfFins !== undefined) {
return 'Fish'
}
throw new TypeError(`Unable to resolve type for Animal with value: ${value}`)
}
If instead of returning simple objects, we return instances of specific classes, we can do even better:
resolveType: (value) => {
if (value instanceof BirdModel) {
return 'Bird'
} else if (value instanceof FishModel) {
return 'Fish'
}
throw new TypeError(`Unable to resolve type for Animal with value: ${value}`)
}
Whatever our conditional logic looks like, just remember that we're always just testing the value being returned by the resolver, whatever that happens to be.
Things get a bit trickier if you're not using classes and two or more of the types share the same structure. Or, as in your case, when the distinguishing property (results
) is an array, since inspecting one of the elements is a no-go. Imagine our union instead looks like this:
union Animal = Cat | Dog
type Cat {
numberOfPaws: Int
}
type Dog {
numberOfPaws: Int
}
Here, unfortunately, we have to rely on our resolver to provide some additional information. For example, we could return some arbitrary field to identify the type:
// Resolver for animal field
resolve: () => {
return {
numberOfPaws: 4,
kind: 'Dog',
}
}
// Union
resolveType: (value) => {
return value.kind
}
But we can actually do one better by relying on the default implementations of resolveType
and isTypeOf
:
resolve: () => {
return {
numberOfPaws: 4,
__typename: 'Dog',
}
}
By explicitly returning the __typename
like this, we can actually omit defining resolveType
altogether. However, keep in mind that, again, this creates a dependency on the resolver. Where possible, you should probably favor using resolveType
with instanceof
checks instead to decouple resolveType
from your resolver logic.
Upvotes: 1