import { Callout } from '@theguild/components'

# Apollo-Server

You can send usage reports to the Hive registry from your Apollo-Server instance using the
`@graphql-hive/apollo` package.

<Callout type="warning">
  In case you want to use Apollo-Server as a Federation gateway, please refer to the [Apollo Gateway
  integration guide](./apollo-gateway.mdx).
</Callout>

## Installation

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

<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 to the Hive registry.
</Callout>

The `@graphql-hive/apollo` package exports a
[Apollo-Server plugin](https://www.apollographql.com/docs/apollo-server/), that can be used
directly.

## Configuration

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

## Integration

### 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

You can report usage to the Hive registry by using the `@graphql-hive/apollo` package. Depending on
your GraphQL server setup the configuration might differ.

<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 filename="Node.js Apollo Server S setup" {8-12,19-21}
import { ApolloServer } from '@apollo/server'
import { startStandaloneServer } from '@apollo/server/standalone'
import { useHive } from '@graphql-hive/apollo'

const testServer = new ApolloServer({
  schema,
  plugins: [
    useHive({
      enabled: true,
      token: 'YOUR-TOKEN',
      usage: true
    })
  ]
})

const { url } = await startStandaloneServer(testServer, {
  // Attach Node.js request to context,
  // learn more in the "Client Information" section.
  async context({ req }) {
    return { req }
  }
})

console.log(`Server listening on ${url}`)
```

This will result in all operations sent to the Apollo Server being reported to the Hive registry.

##### Client Information

In case you want to also associate a client name and version with any operation reported to Hive,
you need to send the `x-graphql-client-name` and `x-graphql-client-version` HTTP headers for
requests to the Apollo Server instance from your client. You must include both of these headers,
otherwise the data will not be passed along.

```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 }"}'
```

<Callout type='info'>
In order for the client information to be sent to the Hive registry, you need to ensure that either
the `req` ([fetch API `Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)),
`request` ([Node.js `IncomingMessage`](https://nodejs.org/api/http.html#class-httpincomingmessage)),
or `headers`
([primitive header name to value map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))
property is within the context object of your server.

Whether you use `req`, `request`, or `headers` depends on the environment you are running your
Apollo Server in. E.g. on Node.js you would add `req` to the context, in a Cloudflare environment,
you would add the `request` property, and in a AWS lambda environment, you would simply add the
`headers` property.

</Callout>

#### GraphQL over WebSocket

Apollo recommends the GraphQL over WebSocket protocol for GraphQL Subscriptions using `graphql-ws`.
Since WebSocket requests are not HTTP requests, additional configuration to the Apollo Server
WebSocket setup is required for proper usage reporting to GraphQL Hive.

The following example demonstrates how to set up the Apollo Server with `graphql-ws` and reporting.

```ts filename="Node.js Apollo Server WebSocket setup" {4,9,22-26,31,32,59}
import { createServer } from 'http'
import bodyParser from 'body-parser'
import express from 'express'
import { execute, subscribe } from 'graphql'
import { useServer } from 'graphql-ws/lib/use/ws'
import { WebSocketServer } from 'ws'
import { ApolloServer } from '@apollo/server'
import { expressMiddleware } from '@apollo/server/express4'
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'
import { createHive, useHive } from '@graphql-hive/apollo'
import schema from './schema'

const PORT = 3000

const app = express()
const httpServer = createServer(app)
const wsServer = new WebSocketServer({
  server: httpServer,
  path: '/graphql'
})

const hiveClient = createHive({
  enabled: true,
  token: 'YOUR-TOKEN',
  usage: true
})

const serverCleanup = useServer(
  {
    schema,
    execute: hiveClient.createInstrumentedExecute(execute),
    subscribe: hiveClient.createInstrumentedSubscribe(subscribe),
    context: context => context
  },
  wsServer
)

const server = new ApolloServer({
  schema,
  plugins: [
    useHive(hiveClient),
    ApolloServerPluginDrainHttpServer({ httpServer }),
    {
      async serverWillStart() {
        return {
          async drainServer() {
            await serverCleanup.dispose()
          }
        }
      }
    }
  ]
})
await server.start()
app.use(
  '/graphql',
  bodyParser.json(),
  expressMiddleware(server, {
    context: async ({ req }) => ({ req })
  })
)

httpServer.listen(PORT, () => {
  console.log(`🚀 Query endpoint ready at http://localhost:${PORT}/graphql`)
  console.log(`🚀 Subscription endpoint ready at ws://localhost:${PORT}/graphql`)
})
```

##### Client Information

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

Please make sure that you follow the GraphQL over WebSocket recipe for the server from the section
above.

```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/apollo` source code](https://github.com/graphql-hive/platform/tree/main/packages/libraries/apollo)
- [`HivePluginOptions` configuration reference](https://github.com/graphql-hive/platform/blob/main/packages/libraries/core/src/client/types.ts)
- [Apollo Server](https://www.apollographql.com/docs/apollo-server/)
