Christoph Haag

Christoph Haag

Christoph ist Softwareentwickler mit einer Passion für Musik

08.04.2022 | 4 min Lesezeit

Live Datenaktualisierung mit GraphQL und WebSockets

Live Datenaktualisierung mit GraphQL und WebSockets blog image

Daten sind selten statisch. Stattdessen ändern sie sich über die Zeit. Der Benzinpreis. Aktien. Ein Messwert eines Sensors. Manche Daten ändern sich sehr häufig und ggf. auch in regelmäßigen Abständen, wie z.B. ein Sensormesswert, andere hingegen eher sporadisch, wie z.B. der Benzinpreis.

In diesem Blogeintrag soll gezeigt werden, wie ein React-Frontend mit GraphQL Live-Daten von einem C# .NET 6.0 Backend erhalten und mit dem Apollo Client konsumieren kann.

Für unser sehr einfaches Beispiel wollen wir die aktuelle Uhrzeit im Backend generieren und im Frontend automatisch aktualisiert anzeigen.

GraphQL

Die Webseite von GraphQL beschreibt sich selbst wie folgt:

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

Entscheidend und spannend an GraphQL ist, dass es sich um eine Abfragesprache für APIs handelt. Also wie SQL für Datenbanken nur eben für APIs. Sprich eine Abfragesprache über Netzwerkgrenzen hinweg. Und der Client bestimmt, welche Daten er erhält. In klassischen REST APIs definiert dies der Server.

Lesen

Beispiel für eine GraphQL Abfrage, die die aktuelle Uhrzeit abfragt:

query {
    currentDateTime
}

Live-Daten

Sollen in einer (REST) API Live-Daten implementiert werden, wird häufig auf Polling zurückgegriffen. Dabei wird in einem regelmäßigen Zyklus von beispielsweise 5 Sekunden ein GET request abgesetzt und somit der neueste Stand der Daten abgefragt und angezeigt. Dies reicht in vielen Fällen vollständig aus und kann insbesondere dann zum Einsatz kommen, wenn das Polling zeitlich befristet ist, die Daten nicht aktuell sein müssen oder nur ein oder sehr wenige Werte gleichzeitig aktuell gehalten werden sollen.

GraphQL bietet hierfür eine weitere Operation an: Subscriptions.

a long-lived request that fetches data in response to source events. --- GraphQL Spezifikation

Da Subscriptions langlebig sind, ist HTTP als Protokoll ungeeignet. Deshalb kommt für Subscriptions in der Regel das WebSockets Protokoll zum Einsatz. In der GraphQL Abfragesprache sehen Subscriptions den Queries sehr ähnlich. Die Abfrage für die aktuelle Uhrzeit sieht wie folgt aus:

subscription {
    currentDateTime
}

Die Vorteile gegenüber Polling via HTTP liegen auf der Hand:

  • schnellstmögliche Aktualiserung der Daten, da eventbasiert
  • eine Verbindung zum Server, auch für mehrere Subscriptions

Apollo Client

Der Apollo Client ist eine Bibliothek, die das Arbeiten mit GraphQL in (React)-Frontends stark vereinfacht.

Apollo Client is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. Use it to fetch, cache, and modify application data, all while automatically updating your UI. --- apollographql.com

Das Demo Projekt

Der Code, um im Backend die Uhrzeit jede Sekunde zu generieren und über eine GraphQL Subscription zur Verfügung zu stellen, sieht wie folgt aus:

public class DemoSubscription : ObjectGraphType
{
    public DemoSubscription()
    {
        Field<StringGraphType>()
            .Name("currentDateTime")
            .Resolve(ctx => (ctx.Source as string)!)
            .Subscribe(ctx => Observable
                .Interval(TimeSpan.FromSeconds(1))
                .Select(x => DateTimeOffset.Now.ToString("s")));
    }
}

Im Frontend schreiben wir eine GraphQL Query für eine Subscription:

import { gql } from "@apollo/client";

const CURRENT_DATE_TIME_SUBSCRIPTION = gql`
  subscription {
    currentDateTime
  }
`;

und übergeben diese über die useSubscription Hook an unseren Apollo Client.

import { useSubscription } from "@apollo/client";

const App = () => {
  const { data, loading } = useSubscription(CURRENT_DATE_TIME_SUBSCRIPTION);

  return (
    <div className="h-screen flex justify-center items-center text-xl">
      {loading && <p>lädt...</p>}
      {data && <p>{data.currentDateTime}</p>}
    </div>
  );
}

Alles weitere ist ein wenig Konfiguration und das Aufsetzen des Projekts. Fertig. Der vollständige Quellcode ist auf Github zu finden.

Fazit

Live-Daten im Frontend zu verwenden scheint oft eine Hürde zu sein. Mit GraphQL Subscriptions über WebSocket, dem Apollo Client und einer .NET API ist in sehr kurzer Zeit alles Nötige getan. Zeit, um es selbst einfach mal auszuprobieren?