koaGraphql(options)
createClient(options)
createServer(options)
execSchema(options)
fetchRemoteSchema(options)
fetchRemoteSchemas(schemas, options)
registerClient(container, client)
registerClients(container, clients)
registerServer(container, models)
collectClientMetrics(options)
examples
GraphQLClient
Every function described above is a top-level export. You can import any of them like this:
import { koaGraphql } from '@meltwater/mlabs-graphql'
Additionally, all modules from GraphQL.js and GraphQL-tools are reexported, and graphql-tag is reexported as the default export for this module, e.g.,
import gql, { graphql, makeExecutableSchema } from '@meltwater/mlabs-graphql'
Koa router for Apollo GraphQL Server GraphQL Playground.
Creates a new Apollo server instance for each request.
The server is created with context
set to the Koa ctx
and assigned to ctx.state.apolloServer
.
The server is created using the following logic:
- If
ctx.state.container
is defined, resolveapolloServer
from the Awilix container.- The passed
options
will be registered asgqlOptions
before resolvingapolloServer
. - The Koa context will be registered as
gqlContext
before resolvingapolloServer
.
- The passed
- If
ctx.state.container
is not defined, look forgqlTypeDefs
,gqlResolvers
, andgqlSchema
inctx.state
and pass tocreateServer
astypeDefs
,resolvers
, andschema
respectively.- If
schema
,resolvers
, ortypeDefs
are passed these will override any corresponding values inctx.state
.
- If
options
(object): Any additional options are passed directly tocreateServer
.schema
(object): The GraphQL schema. Default:null
.typeDefs
(object): The GraphQL type defs. Default:null
.resolvers
(object): The GraphQL resolvers map. Default:null
.middleware
(array): Koa middleware to use after Apollo server starts but before the request is handled.graphqlRoot
(string): Path to serve GraphQL endpoint. Default:/graphql
.subscriptionsRoot
(string): Path to serve GraphQL subscriptions endpoint. Default:/subscriptions
.playgroundRoot
(string): Path to serve GraphQL Playground endpoint. Ifnull
, the endpoint will be unavailable. Default:/playground
.
(object): The router.
graphqlRouter = koaGraphql()
app.use(graphqlRouter.routes())
app.use(graphqlRouter.allowedMethods())
Create an Apollo Server.
Either typeDefs
and resolvers
or a schema
must be provided.
options
(object): Any additional options are passed directly to the Apollo Server.schema
(object): The GraphQL schema. If given will override all other schema-specific options below.typeDefs
(array): The GraphQL type defs. Must be either an array of only strings or an array of only strings tagged withgql
, an array of mixed types is not currently supported.resolvers
(object): The GraphQL resolvers map.remoteResolvers
(object): The GraphQL remote resolvers map.schemaDirectives
(object): TheschemaDirectives
option when creating or merging the schema.mergeInfo
(object): ThemergeInfo
option formergeSchemas
.transformSchema
(function): ThetransformSchema
option formergeSchemas
.onTypeConflict
(function): TheonTypeConflict
option formergeSchemas
.graphqlRoot
(string): Path to serve GraphQL endpoint. Default:/graphql
.subscriptionsRoot
(string): Path to serve GraphQL subscriptions endpoint. Default:/subscriptions
.log
(object): A Logger. Default: one will be created.
(ApolloServer)
Execute a query on a schema (wraps graphql).
options
(object):query
(object): Thegraphql
requestString
argument.schema
(object): Thegraphql
schema
argument.variables
(object): Thegraphql
variableValues
argument.root
(object): Thegraphql
rootValue
argument.context
(object): Thegraphql
contextValue
argument.throwGqlErrors
(boolean): If true, throw when anyerrors
are returned. Default: true.log
(object): A Logger. Default: one will be created.
(object) Promise from the graphql
function.
Fetch a remote schema from a GraphQL endpoint using Apollo Link and makeRemoteExecutableSchema.
Returns a promise.
options
(object):origin
(string required): The GraphQL server URL origin.path
(string): The GraphQL endpoint on the server. Default:/graphql
.token
(string): Token to send in theauthorization
header. Default: none.link
(object): The Apollo Link to use. Default: create a new Apollo HTTP Link.linkOptions
(object): Options passed directly to Apollo HTTP Link iflink
is not provided.schemaOptions
(object): Options passed directly to makeRemoteExecutableSchema. Default: none.
(object):
schema
: The remote executable schema.link
: The Apollo Link for the remote schema.health
: An async function that will fetch a new schema, compare the current schema, and throw if they differ.introspectionQueryResultData
: The data returned from the introspection query.
Fetch remote schemas from a GraphQL endpoint using
fetchRemoteSchema(options)
.
Returns a promise.
schemas
(object): Object where each value is passed tofetchRemoteSchema
.options
: (object): Default options to merge with each schema before passing tofetchRemoteSchema
.
(object): Object with the same keys as schemas
with values replaced by the return of fetchRemoteSchema
.
Create a GraphQLClient. If a link or cache are not provided, they will be created.
The Apollo Client fetchPolicy
option is set to no-cache
by default
for each operation.
options
(object): Any additional options are passed directly to the GraphQLClient.origin
(string): The GraphQL server URL origin. Default: an empty string.path
(string): The GraphQL endpoint on the server. Default:/graphql
.reqId
(string): Request id to send in thex-request-id
header. Default: none.token
(string): Token to send in theauthorization
header. Default: none.log
(object): A Logger. Default: none, but one will be created by the GraphQLClient.cache
(object): The Apollo Cache to use. Default: create a new Apollo InMemoryCache.cacheOptions
(object): Options passed directly to Apollo InMemoryCache ifcache
is not provided.link
(object): The Apollo Link to use. Default: create a new Apollo HTTP Link.linkOptions
(object): Options passed directly to Apollo HTTP Link iflink
is not provided.apolloClientOptions
(object): Options passed directly to Apollo Client.
(GraphQLClient)
const client = createClient({
origin: 'https://example.com',
reqId: null,
log
})
Register a GraphQLClient and its dependencies in the Awilix container.
The container must provide the dependencies registry
, log
and reqId
.
The reqId
will be sent in the x-request-id
header.
The registry
is passed as metricRegistry
to the GraphQLClient.
For example, registering a client named gql
will register the following dependencies:
gqlClientCache
: The Apollo InMemoryCache (singleton).gqlClientHttpLink
: The Apollo HTTP Link (singleton).gqlClientLink
: The Apollo Link (scoped). Combines the HTTP Link and request id header forwarding.gqlClientApolloClient
: The Apollo Client (scoped). UsesgqlClientCache
andgqlClientLink
. ThefetchPolicy
option is set tono-cache
by default for each operation.gqlClient
: The GraphQLClient (scoped). UsesgqlClientApolloClient
.
Any of these dependencies may be overridden manually be registering a compatible dependency under the corresponding name.
container
(object required): The Awilix container.client
(object):name
(string): The (unique) client name. The client will be registered as${name}Client
. Default:gql
.origin
(string): The GraphQL server URL origin. Default: an empty string.path
(string): The GraphQL endpoint on the server. Default:/graphql
.token
(string): Token to send in theauthorization
header. Default: none.cacheOptions
(object): Options passed directly to Apollo InMemoryCache.linkOptions
(object): Options passed directly to Apollo HTTP Link.apolloClientOptions
(object): Options passed directly to Apollo Client.clientOptions
(object): Options passed directly to GraphQLClient.
(undefined)
registerClient(container, {
name: 'foo',
origin: 'https://example.com'
})
const client = container.resolve('fooClient')
Register each GraphQLClient and its dependencies in the Awilix container
using registerClient
.
container
(object required): The Awilix container.clients
(object): The clients to register. Each key will be used as the clientname
and the value will be passed as the second argument toregisterClient
.defaults
(object): Options to apply to each client by default.
(undefined)
Register a GraphQL server and its dependencies in the Awilix container.
The options
argument is optional and will be passed to createServer
.
The container must provide the dependency log
.
Register the following dependencies as well as named dependencies for each model (see below). Any of these may be overridden by re-registering them after calling this method.
gqlTypeDefs
(singleton). PassuseScopedTypeDefs = true
in options to override this.gqlResolvers
(scoped).gqlRemoteResolvers
(scoped).gqlSchemas
(scoped).gqlSchema
(scoped).gqlSchemaDirectives
(scoped).gqlContext
(scoped).gqlOptions
(scoped).gqlExec
(scoped). Function that wrapsexecSchema(options)
and takes the following arguments:query
,operationName
,variables
,context
,apolloServer
(scoped). PassuseScopedServer = false
in options to use singleton.apolloServerStart
: CallswillStart
.apolloServerStop
: Callsstop
.installApolloServerSubscriptionHandlers
: CallsinstallSubscriptionHandlers
for websocket subscriptions support. Depends onserver
as a registered dependency which should be an instance of the Node.js built inhttp.Server
.
Each model is an object containing any or all of
typeDefs
, resolvers
, schema
,
directive
, directiveResolver
, remoteResolver
,
mutation
, and query
.
Each of these should be a factory function which
will be registered in the container and thus may
request dependencies.
(Supplying a constant non-factory functions is also supported.)
The name of the model is its key in the model object
and is prefixed to the registered dependencies.
For example, if the models object has a key Cat
, then
CatTypeDefs
, CatResolvers
, CatRemoteResolvers
, CatSchema
,
CatDirective
, CatDirectiveResolver
, CatMutation
, and CatQuery
may all be registered.
See the example below for the format of each type.
The following properties are added to the context:
container
: The Awilix container scoped to the request.getDep
: Alias forcontainer.resolve
.getDeps
: Function that takes a list of dependency names and resolves them as an object. Additional arguments are passed tocontainer.resolve
.
container
(object required): The Awilix container.models
(object): The models to register.
(undefined)
const Cat = `
type Cat {
name: String
type: CatType
food: FoodType
}
`
const CatType = ({ catTypes }) => `
enum CatType {
${catTypes.join(' ')}
}
`
const typeDefs = ({ catTypes }) => () => [
CatType({ catTypes }),
Cat
]
export const resolvers = ({
FoodQuery
}) => ({
food: (...args) => FoodQuery.get(...args)
})
export const query = ({ catService }) => ({
get: (parent, { id }, context, info) => catService.get(id)
})
export const mutation = ({ catService }) => ({
create: (parent, { input }, context, info) => {
return catService.create(input)
}
})
const catModel = {
typeDefs,
resolvers,
mutation,
query
}
const foodModel = {...} // will define FoodQuery.get(...)
const QueryModel = {...} // will use CatQuery.get(...)
const MutationModel = {...} // will use CatMutation.create(...)
const RootModel = {...} // will define Query and Mutation under schema
registerModels(container, {
Food: FoodModel,
Cat: CatModel,
Root: RootModel
})
Convenient query
and mutate
examples for projects using examplr.
- Each example receives the same options and takes the same arguments (see below).
- The
query
(mutation
) example looks for aqueries
(mutations
) directory underdataRoot
. - The GraphQL query or mutation is loaded from a file matching
${name}.graphql
. The corresponding variables are loaded from a file matching${name}.${vars}.json
. - By default, to support queries without variables,
the special name
default
is used forvars
, in which case there is no error if the variables file is not found.
dataRoot
(string required): Path containing thequeries
andmutations
directories.graphqlOrigin
(string required): The GraphQL server URL origin.graphqlPath
(string): The GraphQL endpoint on the server. Default:/graphql
.graphqlVarTransforms
(object): Functions to transform the variables loaded from the JSON file before making a request. Looks for a transform function underqueries[name]
ormutations[name]
. Each function will receive the variables as an object and should return a new object. Additionally, all arguments passed to the example will be passed to the transform function as additional arguments beyond the first (name
,vars
, etc.). Default: no transforms.graphqlClientOptions
(object): Additional options to pass tocreateClient
. UsedefaultOptions
inside this to directly affect the query or mutation.graphqldefaultNames
(object): Default names to use for queries and mutations. Default:{query: 'query', mutation: 'mutation'}
.log
(object): The Logger.
name
(string): The name of the query or mutation to load.vars
(string): The name of variables to load.
(object): The {data}
result from the query or mutation.
Create examples/mutations/foo.graphql
and examples/mutations/foo.default.json
,
then update an existing set of examplr examples, e.g.,
/* examples/index.js */
import createExamples from '@meltwater/examplr'
import { examples } from '@meltwater/mlabs-graphql'
const envVars = [
'GRAPHQL_ORIGIN',
'DATA_ROOT'
]
const defaultOptions = {
graphqlVarTransforms: {
mutations: {
bar: vars => ({...vars, date: Date.now()})
}
},
graphqlDefaultNames: {query: 'foo', 'mutation': 'bar'},
graphqlOrigin: 'http://localhost:9000',
dataRoot: __dirname
}
if (require.main === module) {
const { runExample } = createExamples({
examples,
envVars,
defaultOptions
})
runExample()
}
Collect metrics with Prometheus client.
Call this function once with a Prometheus Registry instance and pass the same Registry instance to each GraphQLClient that should send metrics to this Registry.
The list of (un-prefixed) metric names is exported as metricNames
.
options
(object):register
(object required): Prometheus registry to use for metrics.prefix
(string): Prefix to prepend to all metric names. Default:graphql_client_
.metricOptions
(object): Override options for each metric. Default: no overrides.
(undefined)
const register = new Registry()
collectClientMetrics({
register,
prefix: 'my_prefix_',
options: {
'request_duration_milliseconds': {
buckets: [0, 200, 300, 800]
}
}
})
const client = createClient({ metricRegistry: register })
await client.query(...)
register.metrics()
All methods are asynchronous (return a promise).
options
(object):apolloClient
(object required): The Apollo Client instance to use for requests.name
(string): The client name (for logging). Default: graphql.retry
(object or number): Options to pass directly to async-retry.metricRegistry
(object): Prometheus Registry to collect metrics. Default:null
(metrics disabled).metricPrefix
(object): Prefix prepend to all metric names. Default: SeecollectClientMetrics
.healthQuery
: Query used for health check. Default: standard type query.reqId
(string): A request id to bind to the instance. Default: one will be generated.reqIdHeader
(string): Name of the header to use for the request id. Default:x-request-id
.reqNameHeader
(string): Name of the header to use for the request name. Default:x-request-name
.responseLogLevel
(string): Log level to log successful responses. If this level is active, then successful responses will be logged according to the other log response options. Default: debug.willLogOptions
(boolean): If true, log additional options passed to the client methods undermeta
. Default: true.willLogResponseProps
(boolean): If true, log props returned bygetLogResponseProps
. Only relevant ifresponseLogLevel
is an active level. Default: true.willLogResponseData
(boolean): If true, logdata
returned bygetLogResponseData
. Only relevant ifresponseLogLevel
is an active level. Default: true.getLogResponseProps
(function): Receives the full response from ApolloClient and returns an object whose properties will be logged at the top level. Only relevant ifresponseLogLevel
is an active level. Default: no additional props are logged.getLogResponseData
(function): Receives the full response from ApolloClient and returns an object whose properties will be logged underdata
. Only relevant ifresponseLogLevel
is an active level andwillLogResponseData
is set. Default: logs the full ApolloClient response.log
(object): A Logger. Default: a new logger.
import ApolloClient from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({uri})
})
const client = createClient({apolloClient})
(boolean): If the client is healthy.
query
(string required): The GraphQL query.options
(object): Options to pass to the Apollo Client query method.
Alternatively, if a single argument is provided as an object, it is passed directly to the Apollo Client query method.
- Failing requests will be retried on certain errors.
- If the query is given an operation name
or
name
is given as an option (in either case above), log messages will include the name and the name will be sent in the request name header. - Pass the
meta
option to log additional properties to themeta
key. - Pass the
logProps
option to log additional properties at the top-level. - The following options may be set per-request to override
the defaults defined by the constructor:
retry
,willLogOptions
,willLogResponseProps
,willLogResponseData
,getLogResponseProps
,getLogResponseData
andresponseLogLevel
.
const query = gql`query Hello { hello }`
// Each call will execute the same query and log 'Query Hello: Start'
// and set the request name to 'Query Hello'.
client.query(query)
client.query(query, {name: 'Hello'})
client.query({query})
client.query({query, name: 'Hello'})
(object): The response.
mutation
(string required): The GraphQL mutation.options
(object): Options to pass to Apollo Client mutate method.
Alternatively, if a single argument is provided as an object, it is passed directly to the Apollo Client mutate method.
- Failing requests will be retried on certain errors.
- If the mutation is given an operation name
or
name
is given as an option (in either case above), log messages will include the name and the name will be sent in the request name header. - Pass the
meta
option to log additional properties to themeta
key. - Pass the
logProps
option to log additional properties at the top-level. - The following options may be set per-request to override
the defaults defined by the constructor:
retry
,willLogOptions
,willLogResponseProps
,willLogResponseData
,getLogResponseProps
,getLogResponseData
andresponseLogLevel
.
const mutation = gql`{ mutation Greeting { setGreeting(name: "Hola") } }`
// Each call will execute the same mutation and log 'Mutation Greeting: Start'
// and set the request name to 'Mutation Greeting'.
client.mutate(mutation)
client.mutate(mutation, {name: 'Greeting'})
client.mutate({mutation})
client.mutate({mutation, name: 'Greeting'})
(object): The response.