Version: Next

Create your own Graphback plugin

You can build your own custom Graphback plugin to:

  • automate additional customisations to the final generated schema
  • build dynamic resolvers
  • create file resources such as client-side queries.

To create your own plugin, start by creating a class that extends GraphbackPlugin.

import { GraphbackPlugin } from 'graphback';
export class MyGraphbackPlugin extends GraphbackPlugin {
...
}

GraphbackPlugin has a number of methods for performing different extensions to your Graphback API.

For the rest of this documentation, we will be using the following business model:

""" @model """
type Note {
id: ID!
title: String!
archived: Boolean!
description: String
"""
@oneToMany(field: 'note')
"""
comments: [Comment]!
}
""" @model """
type Comment {
id: ID!
text: String
archived: Boolean!
description: String
}

transformSchema#

transformSchema lets you make modifications to the current iteration of the GraphQL schema object. In here you can create or modify any type or field in the schema.

As the GraphQLSchema and its types are immutable we highly recommend you to install and use the amazing GraphQL Compose to modify the schema.

import { GraphbackPlugin, GraphbackCoreMetadata } from 'graphback';
import { GraphQLSchema, GraphQLSchema, GraphQLList, GraphQLNonNull } from 'graphql';
import { SchemaComposer } from 'graphql-compose';
export class MyGraphbackPlugin extends GraphbackPlugin {
transformSchema(metadata: GraphbackCoreMetadata): GraphQLSchema {
const schema = metadata.getSchema()
const schemaComposer = new SchemaComposer(schema)
const graphbackModels = metadata.getModelDefinitions()
for (const model of graphbackModels) {
schemaComposer.Query.addFields({
[`getArchived${model.graphqlType.name}s`]: {
type: GraphQLNonNull(GraphQLList(model.graphqlType))
}
})
}
return schemaComposer.buildSchema()
}
...
}

In MyGraphbackPlugin, the transformSchema hook adds a new query field to the schema for each of the data models to retrieve all archived models.

type Query {
getNote(id: ID!): Note
findNotes(filter: NoteFilter, page: PageRequest, orderBy: OrderByInput): NoteResultList!
getComment(id: ID!): Comment
findComments(filter: CommentFilter, page: PageRequest, orderBy: OrderByInput): CommentResultList!
getArchivedNotes: [Note]!
getArchivedComments: [Comment]!
}

createResolvers#

With the createResolvers hook you can create and return resolvers using the graphql-tools format.

To use createResolvers you will first need to install @graphql-tools/utils:

yarn add @graphql-tools/utils

Here createResolvers is creating a new query resolver for each query field added to the schema in transformSchema.

import { GraphbackPlugin, GraphbackCoreMetadata } from 'graphback';
import { GraphbackContext, getSelectedFieldsFromResolverInfo, QueryFilter } from '@graphback/core';
import { GraphQLResolveInfo } from 'graphql';
import { IResolvers, IObjectTypeResolver } from '@graphql-tools/utils';
export class MyGraphbackPlugin extends GraphbackPlugin {
...
createResolvers(metadata: GraphbackCoreMetadata): IResolvers {
const resolvers: IResolvers = {};
const queryObj: IObjectTypeResolver = {};
// loop through every Graphback model
for (const model of metadata.getModelDefinitions()) {
const modelName = model.graphqlType.name;
// create a resolver function for every query field created in `transformSchema`
queryObj[`getArchived${modelName}s`] = async (_: any, args: any, context: GraphbackContext, info: GraphQLResolveInfo) => {
const crudService = context.graphback[modelName];
// create a filter in the GraphQLCRUD format to retrieve only archived Notes
const customFilter: QueryFilter = {
archived: {
eq: true
}
};
// use the model service created by Graphback to query the database
const { items } = await crudService.findBy({ filter: customFilter });
return items;
}
}
resolvers.Query = queryObj;
return resolvers;
}
}

createResources#

Since Graphback is primarily a runtime framework, you probably won't use createResources too often. However it is a very useful method if you ever need to output something to a file, such as your schema.

Here createResources is creating a GraphQL schema file from the schema generated by Graphback.

import { GraphbackPlugin, GraphbackCoreMetadata } from 'graphback';
import { writeFileSync } from 'fs';
import { printSchema } from 'graphql';
export class MyGraphbackPlugin extends GraphbackPlugin {
...
createResources(metadata: GraphbackCoreMetadata): void {
const schema = metadata.getSchema()
const schemaSDL = printSchema(schema)
writeFileSync('./schema.graphql', schemaSDL);
}
}

getPluginName#

Returns a unique name of the plugin. The will be used by plugin registry to uniquely identify the plugin.

import { GraphbackPlugin, GraphbackCoreMetadata } from 'graphback';
import { writeFileSync } from 'fs';
export class MyGraphbackPlugin extends GraphbackPlugin {
...
getPluginName() {
return 'MyGraphbackPlugin';
}
}

Usage#

At application start-up#

To use the plugin, add it to the plugins array in buildGraphbackAPI.

const { resolvers, typeDefs, contextCreator } = buildGraphbackAPI(modelDefs, {
dataProviderCreator: createKnexDbProvider(db),
plugins: [
new MyGraphbackPlugin()
]
});
const apolloServer = new ApolloServer({
typeDefs,
resolvers,
context: contextCreator
})
...

Archived Notes or Comments can be retrieved by the following query:

query archivedNotesAndComments {
getArchivedNotes {
id
title
comments {
id
archived
text
}
}
getArchivedComments {
id
text
note {
id
archived
title
}
}
}

With graphback generate#

Some plugins are designed to be invoked through the Graphback CLI, such as those that output files to the local project. See Plugin Overview.

graphback generate dynamically loads the plugin package by its name defined in the .graphqlrc. For plugin packages that begin with @, due to a limitation where keys in a YAML object cannot begin with @, your plugin documentation should explicitly specify the package name with the packageName configuration value.

...
plugins:
my-cool-plugin:
format: 'graphql'
packageName: '@your-namespace/my-cool-plugin' # Graphabck will load this package instead
outputPath: './src/schema/schema.graphql'