Subscribing For Updates

Fetching data from a GraphQL API subscription, uses web sockets, so is a little more involved than a normal request. See the example below to show how to setup a web socket, add the web socker protocol and send the init message followed by a subscription message. The responses will then come back on the web socket. Ensure each, subscription request sent, has a unique id, as this is returned on the response, so you can tie it to the request.

In this example, we are subscribing to the when the pool total changes. We are requesting the productId, Total Net and Gross amounts, and the currency of the pool. Its worth following the guide Guide and use the GraphQL explorer to see is available on the schema.

C#
using System.Net.WebSockets;
using System.Text;

public class Program
{
    public async static Task Main()
    {
        var url = "wss://hub.production.racing.tote.co.uk/partner/connections/graphql/";
        var token = ""; // API-Key;
        var subscriptionRequest = new // Subscription ID, unique per subscription
        {
            id = "1",
            type = "start",
            payload = new
            {
                query = @"
                        subscription {
                          onPoolTotalChanged {
                            isFinalized
                            productId
                            total {
                              netAmounts {
                                currency {
                                  code
                                }
                                decimalAmount
                              }
                              grossAmounts {
                                currency {
                                  code
                                }
                                decimalAmount
                              }
                            }
                          }
                        }"
            }
        };

        var connectionRequest = new // Initialise connection
        {
            type = "connection_init",
            payload = new { useragent = "my-websocket-client", authorization = "Api-Key " + token }
        };

        using var webSocket = new ClientWebSocket();
        webSocket.Options.AddSubProtocol("graphql-ws");
        webSocket.Options.SetRequestHeader("Authorization", "Api-Key" + token);
        await webSocket.ConnectAsync(new Uri(url), CancellationToken.None);

        await SendWebsocketMessage(connectionRequest, webSocket);
        await SendWebsocketMessage(subscriptionRequest, webSocket);
        Console.WriteLine("Sent subscription request.");

        await ListenForMessages(webSocket);
    }

    private static async Task SendWebsocketMessage(object subscriptionRequest, ClientWebSocket webSocket)
    {
        var requestJson = System.Text.Json.JsonSerializer.Serialize(subscriptionRequest);
        var requestBytes = Encoding.UTF8.GetBytes(requestJson);
        await webSocket.SendAsync(new ArraySegment<byte>(requestBytes), WebSocketMessageType.Text, true, CancellationToken.None);
    }

    private static async Task ListenForMessages(ClientWebSocket webSocket)
    {
        var buffer = new byte[1024 * 4];

        while (webSocket.State == WebSocketState.Open)
        {
            var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            if (result.MessageType == WebSocketMessageType.Close)
            {
                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
                break;
            }

            Console.WriteLine($"Received message: {Encoding.UTF8.GetString(buffer, 0, result.Count)}");
        }
    }
}
Python
import asyncio
import websockets
import json
import ssl

async def main():
    url = "wss://hub.production.racing.tote.co.uk/partner/connections/graphql/"
    token = ""  # API-Key

    subscription_request = {
        "id": "1",
        "type": "start",
        "payload": {
            "query": """
                subscription {
                    onPoolTotalChanged {
                        isFinalized
                        productId
                        total {
                            netAmounts {
                                currency {
                                  code
                                }
                                decimalAmount
                            }
                            grossAmounts {
                                currency {
                                  code
                                }
                                decimalAmount
                            }
                        }
                    }
                }
            """
        }
    }

    connection_request = {
        "type": "connection_init",
        "payload": {"useragent": "my-websocket-client", "authorization" = "Api-Key {token}"}
    }

    # Connect to the WebSocket with headers (graphql-ws protocol and authorization)
    headers = {
        "Authorization": "Api-Key {token}",
        "Sec-WebSocket-Protocol": "graphql-ws"
    }

    async with websockets.connect(url, subprotocols=["graphql-ws"], extra_headers=headers, ssl=ssl.SSLContext()) as websocket:
        # Send connection initialization request
        await send_websocket_message(websocket, connection_request)

        # Send subscription request
        await send_websocket_message(websocket, subscription_request)

        print("Sent subscription request.")

        # Listen for incoming messages
        await listen_for_messages(websocket)

async def send_websocket_message(websocket, message):
    # Serialize the message to JSON and send it
    message_json = json.dumps(message)
    await websocket.send(message_json)

async def listen_for_messages(websocket):
    while True:
        try:
            # Receive message from the WebSocket
            message = await websocket.recv()
            print(f"Received message: {message}")
        except websockets.ConnectionClosed:
            print("Connection closed.")
            break

# Run the asyncio event loop
asyncio.run(main())
Go
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "time"

    "github.com/gorilla/websocket"
)

type ConnectionRequest struct {
    Type    string            `json:"type"`
    Payload map[string]string `json:"payload"`
}

type SubscriptionRequest struct {
    ID      string  `json:"id"`
    Type    string  `json:"type"`
    Payload Payload `json:"payload"`
}

type Payload struct {
    Query string `json:"query"`
}

func main() {
    url := "wss://hub.production.racing.tote.co.uk/partner/connections/graphql/"
    token := "" // API-Key

    subscriptionRequest := SubscriptionRequest{
        ID:   "1", // Subscription ID, unique per subscription
        Type: "start",
        Payload: Payload{
            Query: `
                subscription {
                  onPoolTotalChanged {
                    isFinalized
                    productId
                    total {
                      netAmounts {
                        currency {
                          code
                        }
                        decimalAmount
                      }
                      grossAmounts {
                        currency {
                          code
                        }
                        decimalAmount
                      }
                    }
                  }
                }`,
        },
    }

    header := http.Header{}
    header.Add("Authorization", "Api-Key "+token)

    dialer := websocket.Dialer{
        Subprotocols: []string{"graphql-ws"},
    }

    conn, _, err := dialer.Dial(url, header)
    if err != nil {
        log.Fatal("Error connecting to WebSocket:", err)
    }
    defer conn.Close()

    connectionRequest := ConnectionRequest{
        Type:    "connection_init",
        Payload: map[string]string{"useragent": "my-websocket-client", "Authorization": "Api-Key "+token},
    }

    sendWebsocketMessage(conn, connectionRequest)
    sendWebsocketMessage(conn, subscriptionRequest)

    log.Print("listening for messages")
    listenForMessages(conn)
}

func sendWebsocketMessage(conn *websocket.Conn, message interface{}) error {
    requestBytes, err := json.Marshal(message)
    if err != nil {
        return err
    }

    err = conn.WriteMessage(websocket.TextMessage, requestBytes)
    return err
}

func listenForMessages(conn *websocket.Conn) error {
    for {
        _, message, err := conn.ReadMessage()
        if err != nil {
            return err
        }

        fmt.Printf("Received message: %s\n", message)

        time.Sleep(1 * time.Second)
    }
}
Response
{
  "id": "1",
  "type": "data",
  "payload": {
    "data": {
      "onPoolTotalChanged": {
        "isFinalized": false,
        "productId": "1233fe4d-4f2b-4307-80e1-ed7b336a4716",
        "total": {
          "netAmounts": [
            {
                "currency": {
                    "code": "GBP"
                },
                "decimalAmount": 5005.37
            }
          ],
          "grossAmount": [
            {
                "currency": {
                    "code": "GBP"
                },
                "decimalAmount": 6764.01
            }
          ]
        }
      }
    }
  }
}