# GraphQL requests

Source: https://apigenie.pl/docs/reference/cli/test/graphql
Part of the reference of [test](https://apigenie.pl/docs/reference/cli/test.md).
Its other pages: [Request files](https://apigenie.pl/docs/reference/cli/test/requests.md), [Variables and OAuth 2](https://apigenie.pl/docs/reference/cli/test/variables.md), [Assertions and scripts](https://apigenie.pl/docs/reference/cli/test/assertions.md), [Validation](https://apigenie.pl/docs/reference/cli/test/validation.md), [Generated requests](https://apigenie.pl/docs/reference/cli/test/generate.md), [WebSocket and MQTT requests](https://apigenie.pl/docs/reference/cli/test/websocket-mqtt.md), [Kafka requests](https://apigenie.pl/docs/reference/cli/test/kafka.md), [AMQP requests](https://apigenie.pl/docs/reference/cli/test/amqp.md), [gRPC requests](https://apigenie.pl/docs/reference/cli/test/grpc.md), [Importing collections](https://apigenie.pl/docs/reference/cli/test/import.md), [httpYac compatibility](https://apigenie.pl/docs/reference/cli/test/httpyac.md).

A `GRAPHQL` request has the GraphQL document as its body and, after a blank line, its variables as
a JSON object, as in httpYac and the JetBrains HTTP client. It is sent as a `POST` of
`{"query", "variables", "operationName"}` with `Content-Type: application/json`; `# @operation`
gives the `operationName`. The query can also come from a file (`< ./book.graphql`), without inline
variables then.

```http
# @operation GetBook
GRAPHQL {{host}}/graphql

query GetBook($id: ID!) {
  book(id: $id) {
    title
    author { name }
  }
}

{ "id": "1" }
```

A `POST` whose body starts with `query`, `mutation`, `subscription` or `fragment` is sent the same
way, when it has no `Content-Type` or a JSON or `application/graphql` one; with another
`Content-Type` (`text/plain`) it is sent as written. A `POST` of a JSON body that has a `query` (or
a batch of them) and a `GET` with a `query` parameter are GraphQL requests as they are. Without
`--spec`, GraphQL requests are only sent and asserted on.

## Subscriptions

A `GRAPHQL` request (or a `POST` of a query) whose operation is a `subscription` goes over
WebSocket with the graphql-ws protocol (the `graphql-transport-ws` subprotocol of Apollo Client,
urql and GraphiQL). The URL's `http://` becomes `ws://` and `https://` becomes `wss://`; `ws://`
and `wss://` URLs are taken as written. The headers go with the handshake and, as an object, as the
payload of `connection_init`, where servers look for credentials.

The events are the response, as for a [`WS` region](/docs/reference/cli/test/websocket-mqtt):

- The body is the JSON array of the events (`{"data": ...}` each).
- The status is 101.
- Scripts get `response.messages`.

The subscription ends when the server completes it, after `# @expect` events, or when `# @timeout`
(`--message-timeout`, 5000 ms) has passed; then the client completes it. An `error` message from the
server fails the request with its errors.

```http
# @expect 3
GRAPHQL {{host}}/graphql
Authorization: Bearer {{token}}

subscription OnStory($topic: String!) {
  storyAdded(topic: $topic) {
    id
    title
  }
}

{ "topic": "space" }

?? body $.length == 3
?? body $[0].data.storyAdded.id == 1
```

```text
PASS GRAPHQL http://localhost:4000/graphql -> 1 sent, 3 received (162 ms) OnStory
```

A server that doesn't offer `graphql-transport-ws` fails the request (`no connection: the server
doesn't speak graphql-transport-ws (graphql-ws)`). The legacy `graphql-ws` subprotocol of
`subscriptions-transport-ws` and server-sent events aren't spoken.
