GraphQL Hive Client
GraphQL Hive is a GraphQL schemas registry where you can host, manage
and collaborate on all your GraphQL schemas and operations, compatible with all architecture: schema
stitching, federation, or just a good old monolith.
GraphQL Hive is currently available as a hosted service to be used by all. We take care of the heavy
lifting behind the scenes be managing the registry, scaling it for your needs, to free your time to
focus on the most important things at hand.
Installation
npm install @graphql-hive/client
Basic Usage
Hive Client comes with generic client and plugins for Envelop and
Apollo Server
With GraphQL Yoga
GraphQL Yoga is a cross-platform GraphQL sever
built on top of the envelop engine.
import { useHive } from '@graphql-hive/client'
import { createYoga } from '@graphql-yoga/node'
const server = createYoga({
plugins: [
useHive({
enabled: true,
debug: true,
token: 'YOUR-TOKEN',
reporting: {
author: 'Author of the schema version',
commit: 'git sha or any identifier'
},
usage: true
})
]
})
server.start()
With Envelop
If you're not familiar with Envelop - in "short" it's a lightweight JavaScript library for wrapping
GraphQL execution layer and flow, allowing developers to develop, share and collaborate on
GraphQL-related plugins, while filling the missing pieces in GraphQL implementations.
Here's more on that topic.
import { envelop } from '@envelop/core'
import { useHive } from '@graphql-hive/client'
const envelopProxy = envelop({
plugins: [
useHive({
enabled: true,
debug: true,
token: 'YOUR-TOKEN',
reporting: {
author: 'Author of the schema version',
commit: 'git sha or any identifier'
},
usage: true
})
]
})
With Apollo Server
Thanks to the plugin system it's a matter of adding hiveApollo plugin to ApolloServer instance:
import { ApolloServer } from 'apollo-server'
import { hiveApollo } from '@graphql-hive/client'
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [
hiveApollo({
enabled: true,
debug: true,
token: 'YOUR-TOKEN',
reporting: {
author: 'Author of the latest change',
commit: 'git sha or any identifier'
},
usage: true
})
]
})
With Other Servers
First you need to instantiate the Hive Client.
The collectUsage
method accepts the same arguments as execute function of graphql-js and returns a
function that expects the execution result object.
collectUsage(args)
- should be called when a GraphQL execution starts.finish(result)
(function returned by collectUsage(args)
) - has to be invoked right after
execution finishes.
import express from 'express'
import { graphqlHTTP } from 'express-graphql'
import { createHive } from '@graphql-hive/client'
const app = express()
const hive = createHive({
enabled: true,
debug: true,
token: 'YOUR-TOKEN',
reporting: {
author: 'Author of the latest change',
commit: 'git sha or any identifier'
},
usage: true
})
hive.reportSchema({ schema: yourSchema })
app.post(
'/graphql',
graphqlHTTP({
schema: yourSchema,
async customExecuteFn(args) {
const finish = hive.collectUsage(args)
const result = await execute(args)
finish(result)
return result
}
})
)
Using the registry when Stitching
Stitching could be done in many ways, that's why @graphql-hive/client
provide generic functions,
not something dedicated for stitching. Unfortunately the implementation of gateway + polling is up
to you.
Prerequisites:
HIVE_CDN_ENDPOINT
- the endpoint Hive generated for you in the previous stepHIVE_CDN_KEY
- the access key
The createServicesFetcher
factory function returns another function that is responsible for
fetching a list of services from Hive's high-availability endpoint.
import { createServicesFetcher } from '@graphql-hive/client'
const fetchServices = createServicesFetcher({
endpoint: process.env.HIVE_CDN_ENDPOINT,
key: process.env.HIVE_CDN_KEY
})
startMyGraphQLGateway({
async stitchServices() {
const services = await fetchServices()
return services.map(service => {
return {
sdl: service.sdl,
url: service.url,
checksum: service.id
}
})
},
pollingInSec: 10
})
Using the registry with Apollo Gateway
You can connect your Apollo Gateway with Hive client.
HIVE_CDN_ENDPOINT
- the endpoint Hive generated for you in the previous stepHIVE_CDN_KEY
- the access
import { ApolloGateway } from '@apollo/gateway'
import { ApolloServer } from '@apollo/server'
import { startStandaloneServer } from '@apollo/server/standalone'
import { createSupergraphManager } from '@graphql-hive/client'
const gateway = new ApolloGateway({
supergraphSdl: createSupergraphManager({
endpoint: HIVE_CDN_ENDPOINT,
key: HIVE_CDN_KEY,
pollIntervalInMs: 15_000
})
})
const server = new ApolloServer({
gateway
})
const { url } = await startStandaloneServer({ server })
console.log(`🚀 Server ready at ${url}`)
Usage Reporting configuration
Client Info
The schema usage operation information can be enriched with meta information that will be displayed
on the Hive dashboard in order to get a better understanding of the origin of an executed GraphQL
operation.
GraphQL Yoga Example
import { useHive } from '@graphql-hive/client'
import { createYoga } from '@graphql-yoga/node'
const server = createYoga({
plugins: [
useHive({
enabled: true,
token: 'YOUR-TOKEN',
usage: {
clientInfo(ctx: { req: Request }) {
const name = ctx.req.headers.get('x-graphql-client-name')
const version = ctx.req.headers.get('x-graphql-client-version') ?? 'missing'
if (name) {
return { name, version }
}
return null
}
}
})
]
})
server.start()
Envelop Example
import { envelop } from '@envelop/core'
import { useHive } from '@graphql-hive/client'
const envelopProxy = envelop({
plugins: [
useHive({
enabled: true,
token: 'YOUR-TOKEN',
usage: {
clientInfo(ctx: { req: Request }) {
const name = ctx.req.headers.get('x-graphql-client-name')
const version = ctx.req.headers.get('x-graphql-client-version') ?? 'missing'
if (name) {
return { name, version }
}
return null
}
}
})
]
})
Apollo Server Example
import type { IncomingMessage } from 'http'
import { ApolloServer } from 'apollo-server'
import { hiveApollo } from '@graphql-hive/client'
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [
hiveApollo({
enabled: true,
token: 'YOUR-TOKEN',
usage: {
clientInfo(ctx: { req: IncomingMessage }) {
const name = ctx.req.headers['x-graphql-client-name']
const version = ctx.req.headers['x-graphql-client-version'] ?? 'missing'
if (name) {
return { name, version }
}
return null
}
}
})
]
})
Sampling
Basic sampling
With sampleRate
option, you're able to control the sampling rate of the usage reporting. Setting
it to 0.5
will result in 50% of the operations being sent to Hive. There is no guarantee that
every operation will be reported at least once (see atLeastOnceSampler
).
Default: 1
(100%)
useHive({
,
usage: {
sampleRate: 0.6
}
})
Dynamic sampling
GraphQL Hive client accepts a function that returns a number between 0 and 1. This allows you to
implement dynamic sampling based on the operation's context.
If sampler
is defined, sampleRate
is ignored.
A sample rate between 0 and 1.
0.0
= 0% chance of being sent1.0
= 100% chance of being sent.true
= 100%false
= 0%
useHive({
,
usage: {
sampler(samplingContext) {
if (samplingContext.operationName === 'GetUser') {
return 0.5
}
return 0.7;
}
}
})
At-least-once sampling
If you want to make sure that every operation is reported at least once, you can use the
atLeastOnceSampler
. Every operation is reported at least once, but every next occurrence is
decided by the sampler.
import { useHive, atLeastOnceSampler} from '@graphql-hive/client';
useHive({
,
usage: {
sampler: atLeastOnceSampler({
keyFn(samplingContext) {
return samplingContext.operationName;
},
sampler(_samplingContext) {
const hour = new Date().getHours();
if (hour >= 9 && hour <= 17) {
return 0.3;
}
return 0.8;
}
})
}
})
Self-Hosting
To align the client with your own instance of GraphQL Hive, you should use selfHosting
options in
the client configuration.
The example is based on GraphQL Yoga, but the same configuration applies to Apollo Server and
others.
import { useHive } from '@graphql-hive/client'
import { createYoga } from '@graphql-yoga/node'
const server = createYoga({
plugins: [
useHive({
enabled: true,
token: 'YOUR-TOKEN',
selfHosting: {
graphqlEndpoint: 'https://your-own-graphql-hive.com/graphql',
applicationUrl: 'https://your-own-graphql-hive.com',
usageEndpoint: 'https://your-own-graphql-hive.com/usage'
}
})
]
})
server.start()
The selfHosting
options take precedence over the deprecated options.hosting.endpoint
and
options.usage.endpoint
.