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);