All examples on this page are based on a GraphQL binding instance for a GraphQL API with the following schema:
type Query {
user(id: ID!): User
users: [User!]!
}
type Mutation {
createUser(name: String!): User!
updateUser(id: ID!, name: String!): User
deleteUser(id: ID!): User
}
type Subscription {
userCreated: User!
}
type User {
id: ID!
name: String!
}
The GraphQL API above is deployed to this URL: https://graphql-binding-example-service-kcbreqbsbh.now.sh
The Delegate
class is a binding instance that gives you a lower level API to make GraphQL requests to a GraphQL server.
constructor({ schema, fragmentReplacements, before }: BindingOptions)
Creates a new instance of Delegate
.
schema
(required): An executable instance of aGraphQLSchema
which represents the API that should be abstracted. You can create such an instance by using themakeExecutableSchema
ormakeRemoteExecutableSchema
functions from thegraphql-tools
library. Learn more here.fragmentReplacements
: A GraphQL fragment that's applied to each query, subscription or mutation sent to the abstracted API.before
: A function that's executed before a query, mutation or subscription request is sent to the abstracted API.
Example
const fetch = require('node-fetch')
const { Delegate } = require('graphql-binding/dist/Delegate')
const { HttpLink } = require('apollo-link-http')
const { makeRemoteExecutableSchema } = require('graphql-tools')
const typeDefs = `
type Query {
user(id: ID!): User
users: [User!]!
}
type Mutation {
createUser(name: String!): User!
updateUser(id: ID!, name: String!): User
deleteUser(id: ID!): User
}
type Subscription {
userCreated: User!
}
type User {
id: ID!
name: String!
}
`
// Create the remote schema
const endpoint = `https://graphql-binding-example-service-kcbreqbsbh.now.sh`
const link = new HttpLink({ uri: endpoint, fetch })
const schema = makeRemoteExecutableSchema({ link, schema: typeDefs })
// Create the `before` function
const before = () => console.log(`Sending a request to the GraphQL API ...`)
const delegate = new Delegate({ schema, before })
In this example, we create a new instance of the Delegate
class. First we take our remote endpoint and make an HttpLink
which creates an HTTP transport for this binding. This means all requests to our GraphQL API are transported via HTTP. Next we make a remote schema, meaning the schema and it's API's exist on a remote server. The before
function is unique to the Delegate
class. Use this to execute code prior to a GraphQL request.
before: () => void
A function that's executed before a query, mutation or subscription request is sent to the API. This applies to request
, delegate
and delegateSubscription
. This lets you for example modify the link that's used to reach the API, implement analytics features or add a logging statement before each API request.
request<T = any>(query: string, variables?: {
[key: string]: any;
}): Promise<T>;
request
allows you to send a GraphQL query / mutation to the GraphQL API abstracted by this binding. It is a direct proxy for request
from graphql-request
, a library that enables a low level request pattern for GraphQL servers using fetch
.
query
(required): A string that contains the query or mutationvariables
(optional): All variables that are defined in thequery
string
Example: Sending a createUser
mutation to the API
const mutation = `
mutation CreateUserMutation($name: String!) {
createUser(name: $name) {
id
name
}
}
`
const variables = { name: `Andy` }
delegate.request(mutation, variables)
.then(createUserResult => console.log(JSON.stringify(createUserResult)))
.catch((e) => { console.error(e) })
delegate(operation: QueryOrMutation, fieldName: string, args: {
[key: string]: any;
}, infoOrQuery?: GraphQLResolveInfo | string, options?: Options): Promise<any>;
delegate
allows you to delegate the execution of a query or mutation to the GraphQL API that's abstracted by this binding. This function is often used when building a GraphQL gateway layer.
operation
(required): Specifies whether the root field that's targeted by the delegation is query or mutation.- Possible values:
query
,mutation
- Possible values:
fieldName
(required): The name of the root field that's targeted by the delegation.args
(required): Any arguments to be passed to the root field that's targeted by the delegation.infoOrQuery
(optional): Either a string or theinfo
object - in any case this specifies the selection set for the operation which is send to the GraphQL API that's abstract by this binding.- If not provided, the selection set will contain all scalar fields of the requested type except for those with required arguments.
options
(optional): Theoptions
object can have two fields:transforms
(optional): Allows to perform transformations on theinfo
object or theschema
.context
(optional): Allows to pass additional information to the GraphQL API that's abstracted.
Example: Hardcode the selection set as a string
const args = { name: `Rowan` }
const selectionSet = `{ id, name }`
delegate.delegate(
`mutation`,
`createUser`,
args,
selectionSet
)
.then(createUserResult => console.log(JSON.stringify(createUserResult)))
.catch((e) => { console.error(e) })
delegateSubscription(fieldName: string, args?: {
[key: string]: any;
}, infoOrQuery?: GraphQLResolveInfo | string, options?: Options): Promise<AsyncIterator<any>>;
delegateSubscription
allows you to delegate the execution of a subscription to the GraphQL API that's abstracted by this binding. This function is often used when building a GraphQL gateway layer.
fieldName
(required): The name of the root field that's targeted by the delegation.args
(required): Any arguments to be passed to the root field that's targeted by the delegation.infoOrQuery
: Either a string or theinfo
object - in any case this specifies the selection set for the operation which is send to the GraphQL API that's abstract by this binding.options
(optional): Theoptions
object can have two fields:transforms
(optional): Allows to perform transformations on theinfo
object or theschema
.context
(optional): Allows to pass additional information to the GraphQL API that's abstracted.
Example: Selection set based on the info
object inside a GraphQL resolver
const Subscription = {
userCreatedSub: (parent, args, context, info) => {
return delegate.delegateSubscription(
`userCreated`,
args,
// passing the info AST from the parent resolver
info,
{
context
}
)
}
}
getAbstractResolvers(filterSchema?: GraphQLSchema | string): IResolvers;
For abstract GraphQL Types (Union
, Interface
), you need to add concrete resolvers to the graphql-js server in order to know which concrete type to return.
Note that in addition to the properties and methods in this section, Binding
inherits all properties and methods from the Delegate
class documented above.
Exposes all the queries of the GraphQL API that is abstracted by this binding.
Exposes all the mutations of the GraphQL API that is abstracted by this binding.
Exposes all the subscriptions of the GraphQL API that is abstracted by this binding.
addFragmentToInfo(info: GraphQLResolverInfo, fragment: string): GraphQLResolverInfo
Can be used to ensure that specific fields are included in the info
object passed into the bindings.
Example: Ensure the binding fetches the email
field from the User
.
import ExampleBinding from 'graphql-binding-example'
import { addFragmentToInfo } from 'graphql-binding'
const exampleBinding = new ExampleBinding()
async findUser(parent, args, context, info) {
const user = await exampleBinding.query.user({ id: args.id }, addFragmentToInfo(info, 'fragment EnsureEmail on User { email }'), { context })
return user
}
The Options
type has two fields:
transforms
(optional): Allows to perform transformations on theinfo
object or theschema
.context
(optional): Allows to pass additional information to the GraphQL API that's abstracted.
Schema transforms are a tool for making modified copies of GraphQLSchema
objects, while preserving the possibility of delegating back to original schema.
Transforms are useful when working with remote schemas, building GraphQL gateways, and working with GraphQL microservices.
More information on transforms
can be found here
In GraphQL APIs, context
can be provided to every resolver that holds important contextual information like the currently logged in user, or access to a database. Utilizing context
is extremely crucial for bindings to GraphQL servers that may inherit data from HTTP request headers or encode user-specific information to the request. You then can utilize this in each of your resolvers.
In the example below we pass through context from the incoming GraphQL resolver to the underlying binding.
import ExampleBinding from 'graphql-binding-example'
import { addFragmentToInfo } from 'graphql-binding'
const exampleBinding = new ExampleBinding()
async findUser(parent, args, context, info) {
const user = await exampleBinding.query.user({ id: args.id }, info, { context })
return user
}
You could also stamp these values directly:
import ExampleBinding from 'graphql-binding-example'
import { addFragmentToInfo } from 'graphql-binding'
const exampleBinding = new ExampleBinding()
async findUser(parent, args, context, info) {
// For this request hardcode the user you want to call this api on behalf of.
const user = await exampleBinding.query.user({ id: args.id }, info, { context: {
...context,
'userid': '4792742323',
}})
return user
}