Reputation: 1440
I have the following casus. I make calls to multiple API's of webstores. Each webstore has a his own GraphQLObjectType, as can be seen in the code below.
Code of my current types:
// Amazon
const AmazonType = new GraphQLObjectType({
name: 'amazon',
fields: () => ( {
isbn: { type : GraphQLString},
title: { type: GraphQLString },
author: { type: GraphQLString},
publisher: { type: GraphQLString},
})
});
// itunes
const ItunesType = new GraphQLObjectType({
name: 'itunes',
fields: () => ( {
isbn: { type: GraphQLString },
title: { type: GraphQLString },
author: { type: GraphQLString },
publisher: { type: GraphQLString },
})
});
// query
const checkStores = new GraphQLObjectType({
name:'checkBookInStores',
fields: () => ( {
isbn: {
type: GraphQLString,
},
itunes: {
type: ItunesType,
resolve(parentValue,args){
//console.log(parentValue);
data = itunes.getMetadataItunes(parentValue.isbn);
return data;
}
},
amazon: {
type: AmazonType,
resolve(parentValue, args) {
//console.log(parentValue);
data = amazon.getMetadataAmazon(parentValue.isbn);
return data;
}
},
})
});
//RootQuery
const RootQuery = new GraphQLObjectType({
name:'RootQuery',
fields:() =>( {
checkStores: {
type: new GraphQLList(checkStores),
args: {
id: { type: new GraphQLList(GraphQLString),
},
resolve: function (_, {id}) {
var data = [];
for(var i = 0; i < id.length; i++){
var record = {
"isbn": id[i],
};
data.push(record);
}
return data;
}
}
})
});
//schema
module.exports = new GraphQLSchema({
query: RootQuery
});
However, I want to make a interface to, because I use all those fieldsover and over again. I don't want to repeat myself.
I'm trying to implement an interface (by looking at this issue as an example) but I'm getting the following error:
"Error: \"metadata\" expects field \"isbn\" but \"itunes\" does not provide it.",
The new code:
// interface
const MetadataType = new GraphQLInterfaceType({
name: 'metadata',
fields: () => ({
isbn: { type: GraphQLString },
title: { type: GraphQLString },
author: { type: GraphQLString },
publisher: { type: GraphQLString },
}),
resolveType: (value) => {
console.log('value resolvetype:', value)
if (value instanceof ItunesType) {
return ItunesType;
}
else {
return null;
}
},
});
// itunes
const ItunesType = new GraphQLObjectType({
name: 'itunes',
interfaces: [MetadataType],
fields: () => ({
name: { type: GraphQLString}
}),
isTypeOf: (value) => value instanceof ItunesType,
});
Upvotes: 3
Views: 3097
Reputation: 84857
Extending an Interface basically says "this Type will contain these fields" and GraphQL will enforce that rule when compiling your schema. Unfortunately, those fields still have to be explicitly defined for every type that extends the Interface -- there is no type inheritance in GraphQL.
If you want to avoid repeating yourself, the only thing you can do is take advantage of the fact that your field definitions simply return an object:
const commonFields = {
isbn: { type: GraphQLString },
title: { type: GraphQLString },
author: { type: GraphQLString },
publisher: { type: GraphQLString },
};
const AmazonType = new GraphQLObjectType({
name: 'amazon',
fields: () => commonFields,
});
const ItunesType = new GraphQLObjectType({
name: 'itunes',
fields: () => commonFields,
});
If you had additional fields that were specific to a single type, you could also do something like:
Object.assign({
amazonOnlyField: { type: GraphQLString },
}, commonFields)
Lastly, if you really want type inheritance, you could look into using a supplementary library like GraphQL S2S.
Upvotes: 6