graphql-inherits
graphql-inherits copied to clipboard
@inherits directive for Apollo GraphQL
@inherits Directive for Apollo GraphQL
GraphQL and Apollo Server have no built-in inheritance features.
- The
extendkeyword and Apollo@extendsdirective add fields to existing types and have nothing in common with JavaScript ES6extends. - GraphQL interfaces can't (and are not intended to) share fields or resolvers.
This repo provides a custom directive to achieve inheritance.
@inherits Directive Code
const { ApolloServer, gql, SchemaDirectiveVisitor } = require('apollo-server');
const typeDefs = gql`
directive @inherits(type: String!) on OBJECT
type Car {
manufacturer: String
color: String
type: String
}
type Tesla @inherits(type: "Car") {
manufacturer: String
papa: String
model: String
}
type Query {
tesla: Tesla
}
`;
const resolvers = {
Query: {
tesla: () => ({ model: 'S', type: 'electrical' }),
},
Car: {
manufacturer: () => 'Ford',
color: () => 'Orange',
},
Tesla: {
manufacturer: () => 'Tesla, Inc',
papa: () => 'Elon',
},
};
class InheritsDirective extends SchemaDirectiveVisitor {
visitObject(type) {
const fields = type.getFields();
const baseType = this.schema.getTypeMap()[this.args.type];
Object.entries(baseType.getFields()).forEach(([name, field]) => {
if (fields[name] === undefined) {
fields[name] = { ...field };
}
});
}
}
const schemaDirectives = {
inherits: InheritsDirective,
};
const server = new ApolloServer({
typeDefs,
resolvers,
schemaDirectives,
});
server.listen(9449).then(({ url }) => {
console.log(`Server ready at ${url}`);
});
Sample Query
Query:
query {
tesla {
type
manufacturer
papa
color
model
}
}
Output:
{
"data": {
"tesla": {
"type": "electrical",
"manufacturer": "Tesla, Inc",
"papa": "Elon",
"color": "Orange",
"model": "S",
}
}
}
Limitations
Overriding a resolver requires to declare the field in the derived (child) type.