import { Callout } from '@theguild/components'

# GraphQL-Yoga

GraphQL Yoga is the cross-JavaScript runtime GraphQL server maintained by The Guild. We provide an
easy to use plugin for [GraphQL Yoga](https://the-guild.dev/graphql/yoga-server) to integrate with
Hive.

## Installation

```sh npm2yarn
npm i @graphql-hive/yoga
```

<Callout type="info">
  We recommend installing Hive Client package as a direct dependency of your project, because it
  includes a runtime to send usage reports and schemas to Hive registry.
</Callout>

The `@graphql-hive/yoga` package exports a
[Yoga plugin](https://the-guild.dev/graphql/yoga-server/docs/features/envelop-plugins), that can be
used directly with [GraphQL-Yoga](https://the-guild.dev/graphql/yoga-server).

## Configuration

A full configuration guide can be found in the
["Configuration"](../api-reference/client.mdx#configuration) page.

## Integration Guide

### Publishing Schemas

Please use the [Hive CLI to publish your GraphQL schema](../api-reference/cli.mdx#publish-a-schema).
Follow the [CI/CD instructions](./ci-cd.mdx) for automating the process.

### Usage Reporting

<Callout>
  For more configuration options, such as sampling, please refer to the [Hive client
  configuration](../api-reference/client.mdx#configuration) reference.
</Callout>

#### GraphQL over HTTP (default)

You can send usage reporting to Hive registry by using the `usage` section of the configuration:

```ts
import { createServer } from 'node:http'
import { createYoga } from 'graphql-yoga'
import { useHive } from '@graphql-hive/yoga'
import { schema } from './schema'

const yoga = createYoga({
  schema,
  plugins: [
    useHive({
      enabled: true, // Enable/Disable Hive Client
      token: 'YOUR-TOKEN',
      // Collects and send usage reporting based on executed operations
      usage: true
    })
  ]
})

const server = createServer(yoga)

server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})
```

#### Cloudflare Workers

To use Hive with Cloudflare Workers, you can use
[GraphQL Yoga](https://the-guild.dev/graphql/yoga-server) (as shown below) or use the generic
[Hive client](../api-reference/client#custom-integration) with your own GraphQL server
implementation.

Here's an example of how to use Hive with GraphQL Yoga on Cloudflare Workers:

```typescript
import { createYoga } from 'graphql-yoga'
import { createHive, useHive } from '@graphql-hive/yoga'

export default {
  async fetch(request, env, ctx) {
    const hive = createHive({
      enabled: true, // Enable/Disable Hive Client
      token: 'YOUR-TOKEN',
      usage: true // Collects schema usage based on operations,
      autoDispose: false,
    })

    const yoga = createYoga({
      plugins: [useHive(hive)]
    })

    const response = await yoga.fetch(request, env, ctx)
    ctx.waitUntil(hive.dispose())
    return response
  }
}
```

##### Client Information

You can associate a client name and version with any operation reported to Hive, by sending the
`x-graphql-client-name` and `x-graphql-client-version` HTTP headers for requests sent to your
GraphQL Yoga server.

```bash filename="Example HTTP Request with client headers" {2-3}
curl \
  -H "x-graphql-client-name: my-client" \
  -H "x-graphql-client-version: 1.0.0" \
  -H "content-type: application/json" \
  -H "accept: application/json" \
  -X POST \
  "http://localhost:4000/graphql" \
  -d '{"query":"{ hello }"}'
```

#### GraphQL over SSE

GraphQL over SSE is a popular protocol for executing GraphQL Subscription (and also Mutation and
Query) operations.

No additional configuration is required for sending usage reporting to Hive when using the
[`graphql-sse` plugin](https://the-guild.dev/graphql/yoga-server/docs/features/subscriptions#single-connection-mode).
Just add the SSE plugin to your Yoga server and the usage reporting will be sent automatically.

```ts filename="SSE HTTP Request Client info" {4,10}
import { createServer } from 'node:http'
import { createYoga, type YogaInitialContext } from 'graphql-yoga'
import { useHive } from '@graphql-hive/yoga'
import { useGraphQLSSE } from '@graphql-yoga/plugin-graphql-sse'
import { schema } from './schema'

const yoga = createYoga({
  schema,
  plugins: [
    useGraphQLSSE(),
    useHive({
      enabled: true,
      token: 'YOUR-TOKEN',
      usage: true
    })
  ]
})

const server = createServer(yoga)

server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})
```

##### Client Information

The same rules apply for any other HTTP client, such as Apollo Client, Relay, or any other HTTP.
Just forward send the headers to your server.

```bash filename="SSE HTTP Request with headers" {2-3}
curl \
  -H "x-graphql-client-name: my-client" \
  -H "x-graphql-client-version: 1.0.0" \
  -H "content-type: text/event-stream" \
  -H "accept: text/event-stream" \
  -X GET \
  "http://localhost:4000/graphql/stream?query={__typename}"
```

#### GraphQL over WebSocket

GraphQL over WebSocket is a popular protocol for executing GraphQL Subscription (and also Mutation
and Query) operations.

Use the following example for sending usage reporting to Hive with GraphQL Yoga and `graphql-ws`
([using the official recipe](https://the-guild.dev/graphql/yoga-server/docs/features/subscriptions#graphql-over-websocket-protocol-via-graphql-ws)).

```ts filename="GraphQL Yoga HTTP and WebSocket Setup"
import { createServer } from 'node:http'
import { useServer } from 'graphql-ws/lib/use/ws'
import { createYoga } from 'graphql-yoga'
import { WebSocketServer } from 'ws'
import { useHive } from '@graphql-hive/yoga'
import { schema } from './schema'

const yoga = createYoga({
  schema,
  graphiql: {
    subscriptionsProtocol: 'WS'
  },
  plugins: [
    useHive({
      enabled: true,
      token: 'YOUR-TOKEN',
      usage: true
    })
  ]
})

const httpServer = createServer(yoga)
const wsServer = new WebSocketServer({
  server: httpServer,
  path: yoga.graphqlEndpoint
})

useServer(
  {
    execute: (args: any) => args.rootValue.execute(args),
    subscribe: (args: any) => args.rootValue.subscribe(args),
    onSubscribe: async (ctx, msg) => {
      const { schema, execute, subscribe, contextFactory, parse, validate } = yoga.getEnveloped({
        ...ctx,
        req: ctx.extra.request,
        socket: ctx.extra.socket,
        params: msg.payload
      })

      const args = {
        schema,
        operationName: msg.payload.operationName,
        document: parse(msg.payload.query),
        variableValues: msg.payload.variables,
        contextValue: await contextFactory(),
        rootValue: {
          execute,
          subscribe
        }
      }

      const errors = validate(args.schema, args.document)
      if (errors.length) return errors
      return args
    }
  },
  wsServer
)

httpServer.listen(4000, () => {
  console.log('Server is running on port 4000')
})
```

##### Client Information

When using the `graphql-ws` client, you can use the `connectionParams` object to forward the client
information to the server.

```ts filename="GraphQL over WebSocket client configuration"
import { createClient } from 'graphql-ws'

const client = createClient({
  url: `ws://localhost:400/graphql`,
  connectionParams: {
    client: {
      name: 'my-client',
      version: '1.0.0'
    }
  }
})
```

## Additional Resources

- [`@graphql-hive/yoga` source code](https://github.com/graphql-hive/platform/tree/main/packages/libraries/yoga)
- [`HivePluginOptions` configuration reference](https://github.com/graphql-hive/platform/blob/main/packages/libraries/core/src/client/types.ts)
- [GraphQL Yoga](https://the-guild.dev/graphql/yoga-server)
