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
}
]
}
}
}
}
}