Skip to content
This repository was archived by the owner on Oct 17, 2020. It is now read-only.

Files

Latest commit

f751b15 · Aug 16, 2018

History

History
310 lines (221 loc) · 11.2 KB

02-API-Reference.md

File metadata and controls

310 lines (221 loc) · 11.2 KB

API

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

The Delegate class is a binding instance that gives you a lower level API to make GraphQL requests to a GraphQL server.

Constructor

constructor({ schema, fragmentReplacements, before }: BindingOptions)

Creates a new instance of Delegate.

  • schema (required): An executable instance of a GraphQLSchema which represents the API that should be abstracted. You can create such an instance by using the makeExecutableSchema or makeRemoteExecutableSchema functions from the graphql-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.

Methods

before

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

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 mutation
  • variables (optional): All variables that are defined in the query 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

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.

Properties
  • operation (required): Specifies whether the root field that's targeted by the delegation is query or mutation.
    • Possible values: query, mutation
  • 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 the info 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): The options object can have two fields:
    • transforms (optional): Allows to perform transformations on the info object or the schema.
    • 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) })
<iframe src="https://glitch.com/embed/#!/embed/silver-pilot?path=server.js&sidebarCollapsed=true" alt="silver-pilot on glitch" style="height: 100%; width: 100%; border: 0;"></iframe>

delegateSubscription

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.

Properties
  • 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 the info 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): The options object can have two fields:
    • transforms (optional): Allows to perform transformations on the info object or the schema.
    • 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
      }
    )
  }
}

Learn more about the info object.

getAbstractResolvers

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.

The Binding class

Note that in addition to the properties and methods in this section, Binding inherits all properties and methods from the Delegate class documented above.

Properties

query

Exposes all the queries of the GraphQL API that is abstracted by this binding.

mutation

Exposes all the mutations of the GraphQL API that is abstracted by this binding.

subscriptions

Exposes all the subscriptions of the GraphQL API that is abstracted by this binding.

addFragmentToInfo

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
}

Understanding Options

The Options type has two fields:

  • transforms (optional): Allows to perform transformations on the info object or the schema.
  • context (optional): Allows to pass additional information to the GraphQL API that's abstracted.

Transforms

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

Context

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
}