Blog

GraphQL, .Net und React miteinander verbinden – Teil I.

Mikhail Shabanov
Mikhail Shabanov
2. Dezember 2021

In der Welt der Programmierung gibt es heutzutage viele Technologien und eine große Anzahl von Frameworks, um jede Art von Anwendung für nahezu jeden Bedarf zu erstellen. Aber diese Technologien sind dabei oft in „Schichten“ unterteilt, die sich nur selten überschneiden. In der Webwelt gibt es beispielsweise zahlreiche Javascript-Frameworks, mit denen sich eine lebendige Benutzeroberfläche mit verschiedenen Stilen, Animationen usw. erstellen lassen. Auf der anderen Seite muss z. B. eine Bankensoftware robust und zuverlässig sein und eine große Anzahl von Transaktionen pro Sekunde verarbeiten können. Eine andere Welt sind soziale Netzwerke, die auch bei langsamen Internet und  Geräten viele Inhalte in einer mobilen Umgebung bereitstellen müssen. Doch was wäre, wenn wir versuchen würden, die Stärken der einzelnen Technologien zu nutzen und sie zu kombinieren?

Hallo, ich bin Mikhail von Centigrade. Dies ist der erste Artikel der technischen Blog-Serie über GraphQL Web-API, seine Implementierung in .Net 6.0 und wie es von React-Client verwendet werden sollte.

Unsere Anwendung

Ich möchte kein neues Hello World oder Bookstore Beispiel erstellen, um Graphql, .net und React zu zeigen. Ich möchte real existierende Benutzeranforderungen lösen, die wir in unserem Team haben, um einen echten Anwendungsfall zu haben. Mit allen Vor- und Nachteilen.

Das Home-Office von 2020 bis 2021 hat unseren Lebensstil und unsere Gewohnheiten verändert. Vielleicht waren die IT-Leute die einzigen, die das nicht bemerkt haben. Aber manchmal müssen auch wir noch ein paar Worte miteinander wechseln, ein paar News austauschen, neue Tools, Frameworks und coole Funktionen diskutieren. Seit langem nutzt unser Team einen speziellen Chat in MS Teams, um Informationen über Wissenswertes, Artikel und andere nützliche Informationen auszutauschen. Aber ein solcher Chat ist nicht der richtige Ort für eine „Wissensdatenbank“.

Eine Recherche nach vorgefertigten Lösungen zeigte, dass fertige „Wissensdatenbanken“ eine Vielzahl von Tools mit einem gemeinsamen Nachteil boten – alle diese Anwendungen wurden nicht von uns entwickelt. Lassen Sie uns diesen Nachteil beseitigen und unsere eigene Wissensdatenbank mit blackjack und Hotchocolate erstellen. Und sie „VedaVersum“ nennen! Veda = Wissen | Versum = Universum.

Unsere Anwendung wird haben:

  • Authentifizierungsmechanismus jeden Nutzerlogin.
  • Anzeige von Kartenlisten. Jede Karte soll einen Text und einige Metadaten mit Erstellungszeitpunkt, erstelltem Benutzer, zugewiesenem Benutzer (optional) und zugehöriger Karte (optional) enthalten
  • Panel mit Avatar und Namen und „Glockensymbol“, das anzeigt, ob Sie eine zugewiesene Karte haben
  •  „Wer ist online“-Panel. Sie können sehen, wie andere Nutzer in Echtzeit kommen und gehen.

Warum .Net 6.0?

Da wir eine dezentrale Anwendung erstellen wollen, die die gleichzeitige Arbeit mehrerer Benutzer unterstützen soll, benötigen wir einen „Backend-Dienst“. Wenn wir von Backend sprechen, meinen wir Stabilität, Zuverlässigkeit und Leistung. Es gibt nur wenige Plattformen, die solche Optionen bieten können. .Net von Microsoft ist einer der ausgereiften Player auf diesem Gebiet. Und trotz seiner Reife, ist es mit seiner leichtgewichtigen, plattformübergreifenden Version 6.0 so aktuell wie nie zuvor. Microsoft hat viel getan, um die Einstiegsschwelle in die Technologie zu vereinfachen. Es wurden zahlreiche Tutorials erstellt und die Einrichtung von Werkzeugen und Entwicklungsumgebungen vereinfacht. Microsoft hat bis heute die besten IDEs für Entwickler gebaut. Sie können das klassische Visual Studio und Visual Studio Code oder sogar jede beliebige IDE und Befehlszeilenschnittstelle verwenden. Und die gerade veröffentlichte neue .net Version 6.0 hat offiziellen Langzeitsupport von Microsoft.  Viele Entwickler fangen daher an, .Net in ihren neuen Projekten zu verwenden. Aber es bleibt immer noch das gute alte .Net mit seiner Leistung, der riesigen Codebasis und der großen Anzahl von Drittanbieter-Bibliotheken. Und es gibt immer noch-das-gleiche-C# mit jahrzehntelanger klassischer Programmierung, OOP-Implementierung, Patterns und all den Features, die „bärtige Programmierer“ lieben. Also, ich habe mich hinreißen lassen. Für unsere Anwendung brauchen wir einen klassischen Webserver. Das Asp.Net-Projekt passt hier zu unseren Anforderungen.

Warum GraphQL?

GrapQL ist eine Opensource Abfragesprache für die Web API von Facebook. Sie gewährleistet mehr Flexibilität und Effizienz für die App-Entwickler als die traditionelle REST-API. Sie können Abfragen erstellen und alle Daten oder bestimmte Teilmengen von Daten, die Sie benötigen, mit einer Anfrage abrufen. Der GraphQL-Server liefert Ihnen genau die Daten, die Sie angefordert haben. Dadurch wird das Problem des Überabrufs beseitigt. Subscriptions gehören zu den weiteren GraphQL Killing Features. Die App-Entwickler sind durch den Vorteil einer ganzen Abfragesprache viel flexibler, ohne dass sie auf API-Anpassungen oder -Änderungen warten müssen.  Wir werden sie in unserer Lösung verwenden, um alle Nutzer über Kartenänderungen, Neuzugänge und wenn jemand Ihnen eine Karte zugewiesen hat zu informieren. Auch mit GraphQL haben wir eine Menge anderer angenehmer Out-of-the-Box-Funktionen. Wie z.B. Typüberprüfung, Spielplatz-IDE und eine automatisch generierte API-Dokumentation.

Warum React?

Single Page Applications auf Basis von JavaScript-Frameworks sind fest in unser Leben getreten und haben altmodische UI-Konzepte hinter sich gelassen. Auch hier gibt es ein paar Giganten, die unter den Front-End-Entwicklern sehr beliebt sind. Angular von Google und React von Facebook. Dies sind hervorragende UI-Technologien für die Erstellung interaktiver Anwendungen für das Web, mobile und andere Plattformen. Heutzutage steigt die Bekanntheit von React von Tag zu Tag an. Es wird von Facebook unterstützt und hat eine wachsende Community. Beim Vergleich von React und Angular habe ich festgestellt, dass React leichtgewichtiger, einfacher und deklarativer ist, weil es eine UI-Bibliothek und kein UI-Framework wie Angular ist. Und im Falle unserer einfachen Anwendung können wir mit React eine leistungsstarke UI mit weniger Aufwand erstellen.

 

Der Aufbau der Anwendung

Hier sieht man die grundlegende Architektur der Anwendung:

Application Design

Unsere Anwendung wird ein Backend mit GraphQL API haben, das Entitäten in einer Datenbank speichert. Und Single Page Application (SPA) Client, der mit der API kommunizieren wird. In diesem Artikel werden wir uns auf das Backend konzentrieren. Unser Backend wird zwei Entitäten haben – Benutzer und VedaVersumCard. GraphQL wird einige Abfragen haben, um Benutzer- und Kartenlisten zu erhalten. Und Mutation zum Erstellen oder Aktualisieren der Karte. Und zwei Subscriptions – UserAction (wer kam oder ging), und CardChanged. Alle Details können Sie unten sehen.

Los gehts!

Nachfolgend ist eine Beschreibung von allen Schritten, um ein Projekt von Grund auf selbst zu erstellen. Den fertigen Quellcode für diese Lösung gibt es auf GitHub unter diesem Link

Im Artikel werden wir ein Backend mit GraphQL API von Grund auf erstellen, los gehts!

Zuallererst sollten Sie .Net 6.0 SDK installiert haben. Sie können Visual Studio 22 oder VS Code (oder jede andere IDE, die Sie mögen) mit Dotnet CLI verwenden.

Wir erstellen das Projekt „ASP.NET Core Empty“ mit dem Framework „ASP.NET Core 6.0“ und nennen es VedaVersum

In Visual Studio können wir ein paar einfachen Schritten folgen – starten Sie „Neues Projekt“, wählen Sie „ASP.Net Core Web Application“, dann „ASP.NET Core Empty“, wählen Sie das Zielnetzwerk und geben Sie dem Projekt einen Namen. 

Wenn Sie VS Code verwenden, öffnen Sie die Befehlszeile und führen Sie diese Befehle aus:

md VedaVersum
cd VedaVersum
dotnet new web
code .

Damit wird eine einfache ASP.NET-Anwendung mit 2 Klassen erstellt – Program With Main -Methode, die den Webhost erstellt und ausführt. Und Startup, die 2 Methoden hat. Eine für die Einrichtung aller benötigten Dienste im Dependency Injection Container und die Zweite ist für die Einrichtung der HTTP Request Pipeline. So sieht die anfängliche Configure-Methode aus:

 

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    });
}

ASP.Net ist so aufgebaut, dass jede HTTP-Anfrage eine pipeline von Handlern namens Middleware.Configure durchläuft. Die Configure-Methode beschreibt, welche middleware an der pipeline beteiligt sein wird. Im Moment gibt es nur eine Routing-Middleware und einen einfachen Endpunkt-Handler, der die Anfrage an die Root-Adresse abfängt und als HTTP-Antwort den Klartext „Hello World“ zurückgibt. Wir können die soeben erstellte Anwendung ausführen (in VS Code mit dem Befehl dotnet run) und uns das „Hello World“ im Browser ansehen ?.

So weit, so gut. Das Gerüst unserer API ist fertig, es ist an der Zeit, ihr etwas vernünftiges hinzuzufügen. Beginnen wir mit unserem Datenmodell. Wir erstellen den Ordner Model in unserer Lösung und fügen die Entitäten User, VedaVersumCard, enum VedaVersumCardAction und CardActionMessage hinzu.

 

Eine GraphQL API erstellen

Nachdem wir die wichtigsten Entitäten erstellt haben, ist es an der Zeit, unseren Benutzern die Möglichkeit zu geben, sie zu bedienen. Unser Backend sollte in der Lage sein, Standard-CRUD-Operationen durchzuführen. Dazu gehören das Erstellen neuer Wissensdatenbankkarten, das Lesen vorhandener Karten, das Bearbeiten von Karten, das Löschen von Karten und die Benachrichtigung von Benutzern, wenn ihnen Karten zugewiesen wurden. In Bezug auf GraphQL sollten wir ein Schema und die Methoden definieren, die Daten ändern (Mutations), Methoden, die Daten abfragen (Queries) und Push-Benachrichtigungen vom Server zum Client (Subscriptions). Um das Schema mit Queries, Mutations und Subscriptions mit allen bekannten Plattformen wie .Net zu implementieren, sollten wir Methoden implementieren, die Resolver genannt werden. Und es sollten auch Mapper von nativen Dotnet-Objekten in GraphQL object und input Typen vorhanden sein.

Es gibt mehrere Drittanbieter-Bibliotheken für die Erstellung von GraphQL API mit .Net. Hier eine Liste.

Graphql-dotnet setzt voraus, dass Sie alle ObjectTypes manuell beschreiben. Das bedeutet, dass Sie für jede Dotnet-Business-Entität einen entsprechenden ObjectType haben sollten. Da wir nur zwei Entitäten haben, ist das kein großes Problem. Aber wenn wir ein umfangreiches Datenmodell haben, macht dieser Ansatz die Lösung ein wenig unübersichtlich und kompliziert.

In Hotchocolate werden Objekttypen „darunter“ erstellt, und Sie können dotnet-Geschäftsentitäten direkt in den Resolvern und Mutationen ohne zusätzliche Klassen und Konvertierungen verwenden. Und auch wir werden diese Bibliothek für unsere Lösung nehmen, weil ja jeder Schokolade liebt.

Um es in unserem Projekt zu verwenden, müssen wir zunächst die Hotchocolate-Assembly als Nuget-Paket referenzieren. Sie können den Nuget-Paketmanager in Visual Studio verwenden, um das Paket HotChocolate.AspNetCore hinzuzufügen. In VS Code sollten Sie folgenden Befehl ausführen:

dotnet add package HotChocolate.AspNetCore

Unser GraphQL-API-Dienst wird Queries, Mutations und Subscriptions haben. Um diese zu implementieren, sollten wir drei separate Klassen erstellen – VedaVersumQuery, VedaVersumSubscription und VedaVersumMutation. Im Moment gibt es noch keine Implementierung und ich werde hier nicht den ganzen Code schreiben, später werde ich den Link zur endgültigen Lösung zur Verfügung stellen, damit Sie sie herunterladen und testen können.

Die Abfragen sind also nur einfache c#-Methoden. Zum Beispiel:

 

/// <summary>
/// Returns all cards in the base
/// </summary>
public Task<IEnumerable<VedaVersumCard>> GetAllCards()
{
    // Return mock object so far
    return Task.FromResult<IEnumerable<VedaVersumCard>>(new[] {new VedaVersumCard
    {
        Id = Guid.NewGuid().ToString(),
        Title = "Very First Card.",
        Created = DateTimeOffset.Now,
        Content =
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        UserCreated = Guid.NewGuid().ToString()
    }});
}

Für subscriptions werden wir den InMemorySubscription Mechanismus und ITopicEventSender von HotChocolate verwenden. Um unsere Methode mit diesem Mechanismus zu verbinden, fügen wir zwei Attribute hinzu – Subscribe und Topic. Und das ist alles. So sieht Subscription aus:

 

/// <summary>
/// Subscription event fires when new user arrives online
/// </summary>
/// <returns></returns>
[Subscribe]
[Topic]
public User UserArrived([EventMessage] User user)
{
    return user;
}

In unserer mutation class werden wir ITopicEventSender einfügen und ihn zum Auslösen des subscription event verwenden:

 

/// <summary>
/// Notification about user enter
/// </summary>
public async Task<User> UserEnters(string userId)
{
    // ToDo: Mock implementation.
    var user = new User
    {
        Id = userId,
        Name = "Anakin Skywalker",
        UserImage = "https://static.wikia.nocookie.net/starwars/images/6/6f/Anakin_Skywalker_RotS.png"
    };

    await _iTopicEventSender.SendAsync(
        nameof(VedaVErsumSubscription.UserArrived),
        user);
    return user;
}

Und nun das Wichtigste – die Einrichtung von Diensten und Pipeline-Middleware. Ändern wir die Klasse Startup wie folgt:

 

public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddGraphQLServer()
            .AddInMemorySubscriptions()
            .AddQueryType<VedaVersumBaseQuery>()
            .AddMutationType<VedaVersumMutation>()
            .AddSubscriptionType<VedaVersumSubscription>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app
            .UseWebSockets()
            .UseRouting()
            .UseEndpoints(endpoints =>
            {
                endpoints.MapGraphQL();
            });
    }
}

Wie wir sehen können, erledigt HotChocolate die ganze „Drecksarbeit“ für uns ? Die ConfigureServices-Methode richtet alle benötigten Dienste ein und bindet unsere Query-, Mutation- und Subscription-Klassen ein. Die Configure-Methode richtet die WebSockets-Middleware ein, die für Subscriptions erforderlich ist, und bildet dann den GraphQL-Endpunkt ab.

Wenn Sie schon einmal GraphQL verwendet haben, wissen Sie bereits, dass jeder GraphQL-Endpunkt einige Metadaten bereitstellt, die die API beschreiben. Und es gibt ein paar leistungsstarke Tools wie Graphiql und Playground. Diese Werkzeuge bieten eine Art GraphQL IDE. Sie haben eine ganze Dokumentation als Service über alle queries, mutations, subscriptions und Datentypen, die der Endpunkt out of the box bereitstellt. Und diese Informationen werden auch als Intellisense-Tooltips verwendet, wenn Sie GraphQL-Abfragen in der integrierten Spielwiese dort schreiben. Vielleicht ist Ihnen in den obigen Codebeispielen aufgefallen, dass ich XML-Kommentare mit query-, mutation- und subscription-methoden verwende. Diese Kommentare kann HotChocolate als GraphQL-Methodenbeschreibung erstellen und zu den Endpunkt-Metadaten hinzufügen. Um dies zu erreichen, sollten Sie Ihre VedaVersum.csproj-Datei wie folgt bearbeiten:

<PropertyGroup>
    ...
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Dadurch wird jedes Mal, wenn Sie Ihr Projekt kompilieren, eine Dokumentationsdatei aus diesen XML-Kommentaren erstellt.

Banana Cake Pop IDE

In früheren Versionen der Hotchocolate-Bibliothek gab es eine eingebaute Playground-IDE. Ab der Version 11 haben die Entwickler ihre eigene IDE Banana Cake Pop entwickelt. Wenn Sie nun unsere Anwendung starten und zu localhost:5000/graphql gehen, sollten Sie die Banana Cake Pop IDE sehen. Wenn Sie auf der linken Seite auf eine Buch-Schaltfläche klicken, sehen Sie die gesamte API-Beschreibung.

Api Description

Sie können versuchen, Daten abzufragen:

query data

Um die supscription zu starten, sollten Sie zwei Fenster öffnen, in eines davon diese query schreiben und auf den „Play“ button klicken:

subscription {
  userArrived {
    id
    name
    userImage
  }
}

Schreiben Sie die mutation in das zweite Fenster und klicken Sie auf den „Play“ button klicken:

mutation {
  userEnters(userId: "123-abc") {
    id
  }
}

Im ersten Fenster sehen Sie, dass eine subscription-Meldung erschienen ist:

subscription

Fazit

Wir haben einen Blick darauf geworfen, wie einfach es sein kann, eine GraphQL API mit .Net 6.0 und der Hotchocolate Bibliothek zu erstellen und diese API ohne Single Page Application oder javascript clientseitigen Code abzufragen. Im nächsten Artikel werden wir Autorisierung zu unserer Anwendung hinzufügen, werden alle Daten in der Datenbank speichern, werden alle Vorteile von GraphQL Data Loaders sehen und alle Backend Logik beenden. Der letzte Teil wird sich dann auf das Frontend mit React konzentrieren. Bleibt dran…

Möchten Sie mehr zu unseren Leistungen, Produkten oder zu unserem UX-Prozess erfahren?
Wir sind gespannt auf Ihre Anfrage.

Senior UX Manager
+49 681 959 3110

Bitte bestätigen Sie vor dem Versand Ihrer Anfrage über die obige Checkbox, dass wir Sie kontaktieren dürfen.