The @gramps/gramps
package exports two functions that allow GrAMPS data sources to be combined.
Under the hood, this is done by merging all the of data sources, applying schema stitching as needed, merging context objects, and a few other checks and chores to make it easy for developers to quickly build GraphQL servers from separate data sources.
See the API docs below for the all available options, expected return values, and usage examples.
gramps(options)
The main function exported by the GrAMPS package, this generates GraphQLOptions
as a function that’s consumable by apollo-server
.
The gramps
function accepts an options
object which has the following properties:
options.dataSources
Default: []
An array of GrAMPS data sources to be combined.
options.enableMockData
Default: process.env.GRAMPS_MODE === 'mock'
A boolean value determining whether or not mock resolvers should be added to the schema.
options.extraContext
Default: req => ({})
An optional function that returns additional context to be passed to the resolvers. Must return an object.
options.logger
Default: console
An optional logger tool. Must expose warn
and error
methods.
options.apollo
Default: {}
Under the hood, GrAMPS executes the makeExecutableSchema
(docs) and addMockFunctionsToSchema
(docs) functions from graphql-tools
. It also returns a configuration object for an Apollo server (docs). Use this option to pass additional configuration options to these function calls.
For example, to set allowUndefinedInResolve
to false
for debugging, set the option like this:
const GraphQLOptions = gramps({dataSources: [/* ... */],apollo: {makeExecutableSchema: {allowUndefinedInResolve: false,},},});
NOTE: The typeDefs
and resolvers
arguments to makeExecutableSchema
are set by GrAMPS, so any values set for them in the apollo
options will be overridden.
A function that accepts the request and returns a GraphQLOptions
object. See the apollo-server docs for more information.
A simple example:
import gramps from '@gramps/gramps';import XKCD from '@gramps/data-source-xkcd';const GraphQLOptions = gramps({ dataSources: [XKCD] });// => `GraphQLOptions` is valid config for any flavor of apollo-server
A complete example:
import gramps from '@gramps/gramps';import XKCD from '@gramps/data-source-xkcd';import getPino from 'pino';const pino = getPino({ prettyPrint: true });pino.log = pino.info; // logger must expose a `log` methodconst GraphQLOptions = gramps({dataSources: [XKCD],enableMockData: true,extraContext: req => ({token: req.users.token,}),logger: pino,apollo: {addMockFunctionsToSchema: {preserveResolvers: false,},makeExecutableSchema: {logger: pino,allowUndefinedInResolve: false,},apolloServer: {debug: true,},}});
prepare(options)
In some use cases, it’s better to get GraphQLOptions
as an object instead of a function (for example, if you’re planning to do schema stitching between your data sources).
In those use cases, you can use the prepare
function, which is a named export from @gramps/gramps
.
The prepare
function accepts an options
object that is identical to the gramps()
function’s.
Returns a GraphQLOptions
object that can be passed directly to any Apollo server.
Additionally, it exposes an addContext
method that follows the middleware pattern of (req, res, next) => {}
to allow execution of the extraContext
function.
import Express from 'express';import bodyParser from 'body-parser';import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';import { mergeSchemas } from 'graphql-tools';import { prepare } from '@gramps/gramps';import XKCD from '@gramps/data-source-xkcd';import Numbers from '@gramps/data-source-numbers';const gramps = prepare({dataSources: [XKCD, Numbers],extraContext: req => ({ req }), // adds the request to the context});// Add a field that pulls number trivia for the given XKCD comic’s numberconst linkTypeDefs = `extend type XKCD_Comic {numbers: Numbers_Trivia}`;// Add a resolver to make the above field actually workconst schema = mergeSchemas({schemas: [gramps.schema, linkTypeDefs], // use `gramps.schema` for mergingresolvers: mergeInfo => ({XKCD_Comic: {numbers: {fragment: `fragment XKCDFragment on XKCD_Comic { num }`,resolve: (parent, args, context, info) => {return mergeInfo.delegate('query','trivia',{ number: parent.num },context,info);}}}})});const app = new Express();app.use('/graphql',bodyParser.json(),gramps.addContext, // Add the extra contextgraphqlExpress({schema, // Use the merged schema...context: gramps.context, // ...and the GrAMPS context object}),);app.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));app.listen(8080);