Du betrachtest gerade Tech-Tutorial: WebApi für einen Jurassic Park

Tech-Tutorial: WebApi für einen Jurassic Park

Ich melde mich heute nur mit einem sehr kurzen Beitrag an euch zurück. Denn auf meiner Webseite für meine Programmier-Projekte (da ich Informatiker bin habe ich so etwas … ja) habe ich ein Tutorial hochgeladen für alle die sich für das Thema Webapplikationen, APIs und Datenbanken interessieren. Ich beschreibe dort ausführlich wie man eine API für eine Webapplikation aufsetzt und dabei coole Techniken wie Docker und SQL-Datenbanken nutzt. Wenn euch so etwas also interessiert, dann schaut doch mal dort vorbei.

Das Thema dieser Webapplikation die ich (zum Spaß und nicht für kommerzielle Zwecke!) entwickle ist übrigens: Jurassic Park. Es ist quasi eine Verwaltungs-Applikation um einen Dinopark zu managen. Schritt für Schritt könnt ihr sie nachbauen, wenn ihr schon mal in die Programmierung von Webapps einsteigen wolltet.

Erschaffe deinen Jurassic Park digital...

Aktuell tauche ich gerade in den fesselnden Roman „Dino Park“ von Michael Crichton ein, der als Vorlage für das weltberühmten Meisterwerk von Steven Spielberg „Jurassic Park“ diente. Inspiriert von diesem Buch habe ich die Idee entwickelt, ein Park-Verwaltungssystem ähnlich wie im Roman zu erstellen.

Um dieses Vorhaben umzusetzen, habe ich zunächst überlegt, welche Komponenten ich benötige, darunter eine Datenbank, Models sowie Methoden und Funktionen zur Verwaltung dieser Datenbank. Dabei habe ich mich dazu entschieden, eine WebAPI als Grundlage für ein Angular-Frontend-Projekt zu verwenden.

Die Umsetzung erfolgt mithilfe von ASP.NET und C#. Als Datenbanklösung habe ich mich für PostgreSQL entschieden, eine Open-Source-Lösung, die in einem Docker-Container läuft. Dies ermöglicht eine flexible und skalierbare Bereitstellung der Datenbank.

In diesem Artikel/Tutorial werde ich zeigen, wie eine solche Klasse aufgebaut ist und wie sie mit der PostgreSQL-Datenbank verknüpft wird. Des Weiteren erkläre ich, wie die Methoden entwickelt werden, um die Datenbank zu steuern, und wie Controller für die API geschrieben werden. Außerdem zeige ich den Prozess, wie man einen Docker-Container für PostgreSQL einrichtet.

Begleitet mich auf dieser spannenden Reise der Entwicklung eines Park-Verwaltungssystems und tauchen Sie ein in die faszinierende Welt von „Dino Park“!

Docker und Postgres vorbereiten

Ich beginne zu Anfang damit die Grundlage meines Verwaltungssystems vorzubereiten: die Datenbank. Um diese nicht auf meinem Host-System direkt laufen zu lassen und mir langwierige Installationen zu ersparen nutze ich Docker  um einen Container mit dieser Datenbank laufen zu lassen. Da für ein späteres Hosting mit Kubernetes es ohnehin von Vorteil ist, dass die Datenbank, sowie Front- und Backend als Container bereitgestellt werden, ist dies kein unbegründeter Aufwand. Um die Datenbank unabhängig meiner API managen zu können benutze ich die Software pgAdmin.

Der YAML-Code, welcher einen Docker-Container bereitstellt in dem anschließend die postgresql-Datenbank ausgeführt wird. Dieser wird in einem Terminal mit dem Befehl docker compose up ausgeführt.

Anschließend müssen wir nur noch den Docker-Container mit einem DBMS-Verwaltungstool unserer Wahl (ich nehme pgAdmin) verbinden. Der Host ist die IP unseres Localhost (127.0.0.1) und die Zugangsdaten haben wir im Docker-Container-YAML ja bereits angegeben.

Datenbankverbindungen in Visual Studio 2022

Nachdem wir ein neues Projekt angelegt haben (Web-API Projekt mit ASP.NET). Müssen wir einige NuGet-Pakete nachinstallieren um ungestört arbeiten zu können. Die wichtigsten zu installierenden NuGet-Packages sind:

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
  • Npgsql.EntityFrameworkCore.PostgreSQL

Diese Pakete werden für die Kommandozeile und für den Quellcode benötigt um Befehle aus diesen nutzen zu können, oder die Connection zu unserer Datenbank herzustellen. 

Als Nächstes können wir direkt damit beginnen die Verbindung zu unserer Datenbank herzustellen. Um dies zu schaffen benötigen wir einzelne Schritte die da wären:

  1. Connection-String in den appsettings.json anlegen
  2. Datenbank-Context Klasse anlegen, welche die Informationen für die Datenbank bereitstellt und die Zugriffe auf die Tabellen verwaltet.
  3. Connection in der Program.cs herstellen.

Fangen wir also damit an einen Connection-String zu initialisieren. Ich habe meinen in den appsettings.Development.json geschrieben alles was dort drinsteht überschreibt gleichbenannte Eigenschaften in der appsettings.json Datei.

Server und Port (hier auf Standard-Werte gesetzt) müssen an den Docker-Container angepasst werden, bzw. der Umgebung wo dieser ausgeführt wird. Username und Password wurden bereits in der YAML-Datei festgelegt und den Namen der Datenbank können wir uns frei wählen. Weiter geht es mit der Context-Class. 

Die Context-Klasse erbt von DbContecxt und übernimmt auch dessen Standard-Constructor wie im Code-Ausschnitt zu sehen. Die DbSet<> stellen die Tabellen unserer Datenbank da und werden per Klassen initialisiert (also zwischen <> steht der Klassenname – diese erstellen wir im nächsten Schritt) und dahinter steht der Tabellenname. Getter und Setter zur Verwaltung dieser Tabellen müssen ebenfalls hinzugefügt werden. Die Klassen die ich erstellt habe sind Klassen für: Dinosaurier (als Art), Dino-Klasse (also übergeordnete Art), die Fundorte dieser Dinos (Locality), das Erdzeitalter ihrer Existenz (Period), das Gehege im Park (Habitat), das jeweilige Tier (ParkAnimal -> wird später einen Bezug zum Dinosaurier als Art haben), die Mitarbeiter, die sich um diesen Park kümmern und FileReferences für Bilder und Dateiein im Zusammenhang mit den Dinosauriern. Nun müssen wir den Datenbank-Context noch mit dem Connection-String in der Program.cs verbinden.

Eine Klasse erstellen

Als nächsten können wir direkt damit loslegen eine Klasse für unsere Datenbank zu bauen (eine Entität innerhalb der Datenbank). Dies geschieht mit einfachem C#-Code.

Der Datentyp GUID stellt eine sogenannte UUID dar. Eine 128-Bit große ID, die eindeutig ist. Dies bietet eine Menge Vorteile gegenüber der Integer-ID, wie zum Beispiel, dass Daten sich nicht doppeln können, wenn man von Hand eine ID erzeugen muss (in C# mit Guid.NewGuid()). So kann es nicht passieren, dass man versehentlich eine ID 2x vergibt. Das [Key] Attribut besagt, dass es sich beim darauffolgenden Eintrag um den Primary-Key des Datensatzes/der Tabelle handelt. Foreign-Keys, also Fremdverweise werden ganz einfach mit C#-Logik und der Fremdklasse als Datentyp innerhalb der Klasse gelöst, wie man es beispielsweise beim Thumbnail sieht (also dem späteren Vorschaubild), welches vom Typ FileReference ist, was ebenfalls eine Klasse und eine Datenbank-Entität darstellt. Das ? hingegen zeichnet das Feld als nullable aus, es kann also auch den Wert null annehmen. Dies trifft sich für Daten wie dem Thumbnail, da dieses nur optional vergeben werden soll.

Methoden zum Steuern der API

Damit wir die API später auch bedienen können benötigen wir 3 Sachen: 

  • Ein Interface, welches für jede Klasse (wie Dinosaurier) eine gewisse Programm-Logik voraussetzt.
  • Eine Service-Klasse, welche die vorausgesetzten Methoden des Interfaces implementiert.
  • Einen Controller, welcher die API ansteuert und die Funktion der Klasse und des Interfaces nach außen hin bereitstellt.

Hier sehen wir exemplarisch das Interface IDinosaurService, welches die Methoden zur Verwaltung der Tabelle Dinosaur bereitstellen wird. Die Datentypen CreateDinosaurModel und UpdateDinosaurModel sind von mir erstellte Hilfsklassen, welche Informationen enthalten, die vom Frontend kommen sollen, um eine neue Entität eines Dinosauriers anzulegen. Die Klasse DinosaurDetails ist eine Hilfsklasse die die Daten des Dinsoauriers enthält, der von der Datenbank ausgelesen wurde. Also Informationen die ans Frontend zurückgegeben werden, denn das direkte Model gibt man nicht zurück. ResponseModel ist eine Befehlsklasse um den Nutzer auf etwaige Fehler, oder den Erfolg seiner Operation hinzuweisen.

Nachfolgend zu sehen ist ein kleiner Auszug aus der „Helper-Methode“. Diese richtet sich natürlich nach den Eigenschaften, welche ihr im Dino implementiert…

Hier sehen wir einen Ausschnitt wie die Klasse DinosaurService die Methoden seines Interfaces implementiert. Die Behelfmethode, die privat gesetzt ist um nur von der Klasse DinosaurService, behandelt die Umwandlung des Entity-Models aus der Datenbank in ein Info-/oder Details-Model für das Frontend. Wir sehen spezielle LINQ-Befehle, eine Bibliothek für C# um SQL-Befehle auszuführen. Quasi eine Mittelssprache zwischen SQL und C#.

API-Controller erstellen und Interface mit Klasse verknüpfen

Im vorletzten Schritt stellen wir noch den Controller für unsere API bereit. Dieser handelt die eingehenden Aufrufe der API und verknüpft diese mit den Klassen und Interfaces.

Wir sehen einen Controller-Aufruf für die GET-Methode GetAllDinosaurs, welche dazu dient (bspw. für eine Listenansicht im Frontend) alle Dinosaurier aus der Datenbank abzurufen und zurückzugeben. Die Behelfsmethode um das Thumbnail eines jeden aus der Datenbank zu laden (falls vorhanden) zeigt auf eine Methode im Controller für die FileReferenceService-Klasse, also der Klasse um die Dateien (hier eine Bilddatei) der Datenbank zu verwalten. Nun müssen wir nur noch die Verknüpfung zwischen Interface und Klasse in der Program.cs herstellen.

Datenbank-Migration erstellen

Als letztes bleibt uns nur noch, die Migration zwischen Backend und der Datenbank, zu der wir unseren Connection-String gelegt haben, umzusetzen. Hierfür ist nicht mehr vielmehr nötig als ein Terminal (im Projektordner), oder die NuGet-PackageManager-Konsole in Visual Studio zu öffnen. Dann tippen wir nacheinander die Befehle ein:

Hiermit legen wir eine Migration für die Datenbank an. Der Name initial ist frei wählbar. Kommt drauf an wie man diese Migration nennen möchte. Jedoch eignet sich der Name für die erste, initiale Migration bestens.

Anschließend wird unsere Datenbank aktualisiert. Die Datenbank prüft ob sie die neueste Migration im Speicher hat. Wenn dem nicht so ist, dann lädt sie die neueste und bringt die Datenbank auf den neuesten Stand. ACHTUNG: Hier kann es schnell zu Konflikten kommen. Jede Migration sollte also vorausschauend geplant und durchgeführt werden.

Dann können wir unsere API schon starten und sie mit unserem Frontend-Projekt nutzen.

brockAutor

Ich bin ein Schriftsteller aus Chemnitz in Sachsen, der auf klassische Fantasy und Science Fiction steht. Aufgewachsen mit eben solchen Geschichten, schreibe ich meine Geschichten in eben diesen Stil. Während der Mainstream immer weiter mit erzwungener Diversity und Quotenpolitik jegliches Fantasy-Franchise in eine Tele5-Telenovela verwandelt gibt es in meinen Geschichten noch die wahren Werte wie Freundschaft, Liebe, Vernunft, Respekt und die Abenteuer, welche wir schon als Kind liebten.

Schreibe einen Kommentar