$ npm install graphql-binding
🔗 GraphQL bindings are modular building blocks that allow to embed existing GraphQL APIs into your own GraphQL server. Think about it as turning (parts of) GraphQL APIs into reusable LEGO building blocks.
The idea of GraphQL bindings is introduced in detail in this blog post: Reusing & Composing GraphQL APIs with GraphQL Bindings
yarn add graphql-binding
Binding
constructor(options: BindingOptions): Binding
BindingOptions
has the following properties:
Key | Required | Type | Default | Note |
---|---|---|---|---|
schema |
Yes | GraphQLSchema |
- | The executable GraphQL schema for binding |
fragmentReplacements |
No | FragmentReplacements |
{} |
A list of GraphQL fragment definitions, specifying fields that are required for the resolver to function correctly |
before |
No | () => void |
(() => undefined) |
A function that will be executed before a query/mutation is sent to the GraphQL API |
handler |
No | any |
null |
The handler object from JS Proxy |
subscriptionHandler |
No | any |
null |
... |
binding.query.<rootField>(): Promise<any>
& binding.mutation.<rootField>(): Promise<any>
A binding object exposes two properties which can be used to send queries and mutations to the API: binding.query
and binding.mutation
.
Both are of type QueryMap
and will expose methods that are named after the schema's root fields on the Query
and Mutation
types.
These methods take three arguments:
Name | Required | Type | Note |
---|---|---|---|
args |
No | [key: string]: any |
An object that contains the arguments of the root field |
context |
No | [key: string]: any |
The context object that's passed down the GraphQL resolver chain; every resolver can read from and write to that object |
info |
No | GraphQLResolveInfo | string |
The info object (which contains an AST of the incoming query/mutation) that's passed down the GraphQL resolver chain or a string containing a selection set |
Assume the following schema:
type Query {
user(id: ID!): User
}
type Mutation {
createUser(): User!
}
If there is a binding
for a GraphQL API that implements this schema, you can invoke the following methods on it:
binding.query.user({ id: 'abc' })
binding.mutation.createUser()
When using the binding in a resolver implementation, it can be used as follows:
findUser(parent, args, context, info) {
return binding.user({ id: args.id }, context, info)
}
newUser(parent, args, context, info) {
return binding.createUser({}, context, info)
}
binding.subscription.<rootField>(...): AsyncIterator<any> | Promise<AsyncIterator<any>>
The binding.subscription
property follows the same idea as query
and mutation
, but rather than returning a single value using a Promise
, it returns a stream of values using AsyncIterator
.
It is of type SubscriptionMap
and will expose methods that are named after the schema's root fields on the Subscription
type.
These methods take same three arguments as the generated methods on query
and mutation
, see above for the details.
binding.getAbstractResolvers(filterSchema?: GraphQLSchema | string): IResolvers
In order to have support for custom abstract Types like Interface
or Union
, the getAbstractResolvers
method can be used.
The returned resolver then have to be included in the resolvers of the application:
const typeDefs = importSchema('app.graphql')
const resolvers = {
Query: {
hello: (parent, { name }) => `Hello ${name || 'World'}!`,
},
// the following is needed to make interfaces, unions & custom scalars work
...binding.getAbstractResolvers(typeDefs),
}
utils
addFragmentToInfo(info: GraphQLResolverInfo, fragment: string): GraphQLResolverInfo
Can be used to ensure that specific fields are included in the info
object passed into the bindings.
import {addFragmentToInfo} from 'graphql-binding'
async findUser(parent, args, context, info) {
const user = await binding.user({ id: args.id }, context, addFragmentToInfo(info, 'fragment EnsureEmail on User { email }'))
if (blackList.includes(user.email)) {
throw new Error('This user is blocked')
}
return user
}
const { makeExecutableSchema } = require('graphql-tools')
const { Binding } = require('graphql-binding')
const users = [
{
name: 'Alice',
},
{
name: 'Bob',
},
]
const typeDefs = `
type Query {
findUser(name: String!): User
}
type User {
name: String!
}
`
const resolvers = {
Query: {
findUser: (parent, { name }) => users.find(u => u.name === name),
},
}
const schema = makeExecutableSchema({ typeDefs, resolvers })
const findUserBinding = new Binding({
schema,
})
findUserBinding.findUser({ name: 'Bob' }).then(result => console.log(result))
You can find practical, production-ready examples here:
Note: If you've created your own GraphQL binding based on this package, please add it to this list via a PR 🙌
If you have any questions, share some ideas or just want to chat about GraphQL bindings, join the #graphql-bindings
channel in our Slack.
© 2010 - cnpmjs.org x YWFE | Home | YWFE