Programmierung
•
Nov 9, 2020

Adrian Pilarczyk
Senior Backend-Entwickler
JamStack boomt mit Tools wie Next.js und Hasura. Sie denken, nur weil Sie React kennen, heisst das, dass Sie für den Rest deines Lebens To-Do-Listen erstellen werden? Ich habe einige Neuigkeiten für Sie.
Um nicht aus dem gängigsten Webentwicklungsklischee auszubrechen, Tiere als Gegenstand eines lustigen Nebenprojekts zu verwenden, werden wir eine einfache Hundeheim-Website erstellen. Sie wird vorerst aus drei Seiten bestehen: der Startseite, der allgemeinen /Hunde
-Ansicht und der Detailansicht eines einzelnen Hundes. In diesem Blog-Post werden wir API-mässig nur die Daten mit einer GraphQL-Abfrage auslesen - keine Mutationen oder Abonnements (noch).
Das allgemeine Ziel ist es, eine ordentliche Grundlage für eine SSR-React-Anwendung zu präsentieren, die Sie später für einige grössere Projekte verwenden können. Wir werden Next.js + TypeScript als UI-Framework verwenden und unsere Daten werden in einem Service namens Hasura gespeichert, von dem wir sie über eine automatisch generierte GraphQL-API abrufen werden.
Ich werde nicht zu viel Zeit darauf verwenden, irgendetwas Auffälliges zu tun, zumindest nicht am Anfang dieser Serie, wenn Sie also hier sind, um Ihre Augen zu erfreuen, kann ich Ihnen wohl nur empfehlen, zum Ende dieser Seite zu scrollen und sich dort mit einem hübschen Kerl zu treffen. Die Richtung dieser Initiative ist jedoch ganz Ihnen überlassen - wenn Sie das Gefühl haben, dass ich damit irgendwohin gehen soll, lassen Sie es mich einfach auf Twitter wissen: @pilarenko.
Sie können von mir erwarten, dass ich Sie nicht im Regen stehen lasse, mehrere Schritte im Prozess überspringe und davon ausgehe, dass Sie alles wissen, aber ich muss Sie warnen die elementaren React-, TypeScript- und GraphQL-Kenntnisse sind ratsam. Ich werde mein Bestes tun, um die Best Practices bei der Verwendung dieser Tools zu befolgen, aber Sie können gerne einen Pull Request erstellen, wenn etwas zusätzliche Arbeit benötigt. Das Repository ist hier verfügbar.
Inhalt
Next.js + TypeScript-Anwendung einrichten
Grundlegende Einrichtung (kann mit
npx create-next-app
übersprungen werden)Hinzufügen von TypeScript
Hinzufügen von Routen
Hasura Backend einrichten
Next.js + Hasura
Umgebungsvariablen
Vom Server zum Client
Apollo-Konfiguration
useFetch
Daten auf der Server-Seite abrufen
Deploy
Nützliche Links
1. Next.js + TypeScript Anwendung einrichten
1.1 Grundlegende Einrichtung
Ich habe mich entschieden, das gesamte Projekt von Grund auf neu zu starten, weil 1) ich denke, dass es lehrreich sein könnte 2) die App so einfach ist, dass es nicht notwendig ist, eine Vorlage aus dem offiziellen Next.js-Repository zu schnappen, nur um im ersten Schritt die Hälfte des Boilerplates zu pflügen. Also nehmen wir das gute alte:
Sie können "das CLI eingeben", da die Fragen, die das CLI stellt, für unser Projekt nicht super relevant sind. Am Ende haben wir einen package.json
, der dringend seine ersten Abhängigkeiten braucht. Bringen wir sie:
Lassen Sie uns auch eine .gitignore
-Datei erstellen und wir fügen dort unseren Chunky Boi node_modules
ein.
Dann müssen wir package.json
bereitstellen, um Next-Skripte hinzuzufügen, die für die Ausführung des Projekts oder die Erstellung benötigt werden.
Die Struktur der Next.js Anwendung dreht sich um die Verwendung des Verzeichnisses pages
für die Definition der Routen. Das bedeutet, dass jede .jsx/.tsx-Datei, unabhängig davon, wie tief sie in ihren eigenen Unterordnern verschachtelt ist, einer Unterroute entspricht. Fürs Erste erstellen wir die Homepage ("/"), die Next.js als pages/index.jsx
erwartet.
Und lassen Sie uns das mit etwas grundlegendem React auffüllen:
Hatte ich Ihnen nicht gesagt, dass es TypeScript geben würde? Keine Sorge, ich erinnere mich. Lassen Sie uns nur schnell überprüfen, ob alles wie erwartet funktioniert und wir werden es in .tsx
konvertieren. Führen Sie folgendes aus:
und hoffentlich Zeuge dieser Schönheit werden:

Aber das ist nicht das Einzige, was Sie sehen werden - Ihr Auge wird wahrscheinlich das Erscheinen von.next
folder bemerken.

Was sich darin befindet, sind alle Dev-Build-Dateien, die Next.js für uns generiert, um bequem mit der Anwendung lokal zu arbeiten. Schauen Sie nicht hinein, es ist in Elbisch geschrieben. Das Beste, was Sie tun können, ist .next
zu .gitignore
hinzuzufügen.
1.2 Hinzufügen von TypeScript
Nun, lasst uns endlich zu TypeScript kommen und die süsse Next.js Magie nutzen. Geben Sie …
… ein, um eine Datei zu erstellen, die zur Angabe von Compiler-Optionen für TypeScript verwendet wird. Von diesem Moment an wird Next.js Sie durch den Rest führen. Zunächst müssen Sie sich nicht einmal um das Ausfüllen der Konfiguration kümmern, denn sobald Sie npm run dev
erneut starten, wird sie automatisch erzeugt. Wenn Sie das nächste Mal einen Blick darauf werfen, werden Sie etwas ähnliches wie das hier sehen:
Dann überprüfen Sie die Konsole auf die Liste der Pakete, die zur Fertigstellung des Setups erforderlich sind. Höchstwahrscheinlich werden es die Folgenden sein:
Das erste ist der Star selbst, gefolgt von Typdefinitionen für React und Node, die wir in unserer Entwicklungsumgebung nutzen können.
Schön, oder? Nachdem wir tsconfig abgedeckt haben, ist es endlich an der Zeit, den Abzug für die Änderung der Erweiterung zu betätigen, also lassen Sie uns index.jsx
in index.tsx
umwandeln.
Die Änderung der Erweiterung bringt an sich nichts, aber ich schlage vor, dass wir unsere schöne Liebesgeschichte zwischen React und TypeScript beginnen, indem wir den Typ von React Functional Component (React: FC
) zu unserer Index
Funktion ändern. Sie tut noch nichts, aber das ist normalerweise die Geschichte mit TypeScript - sie ist nutzlos, bis sie es nicht ist.
1.3 Hinzufügen von Seiten
Nun, da wir unsere Indexseite haben, fügen wir die restlichen Unterrouten hinzu, beginnend mit /dogs
.

Die Art und Weise, wie ich mir die Anwendung vorstelle, ist, den Benutzer auf die hundespezifische Detailseite umzuleiten, nachdem er auf das Miniaturfoto des Hundes auf der /dogs
Seite geklickt hat. Dazu benötigen wir die besagte Hundedetailseite, die an der ID des Hundes erkannt wird. Wir erwarten, dass die URL etwa so aussieht: www.dog-shelter.com/dog/f1297fb9-1097-45be-a0a3-6ca63f5a8ed9
, wobei nach dem Teil "/dog/" die UUID steht, die dynamisch ist - sie ist für jeden Hund anders. Wir können das in Next.js-Routen durch die Klammer-Syntax übersetzen, wobei wir den dynamischen Parameter in einer [Klammer] halten. Der Pfad für unsere einzelne Hundekomponente sollte also wie folgt aussehen:
Vorübergehend wird nur die ID des „Hundes“ mit Hilfe des useRouter
-Hooks aus der URL gelesen und in der Komponente angezeigt. Das kann wie folgt aussehen:

So sollte unser aktueller Ordner pages
dieser Struktur folgen:

Nun haben wir eine einfache Next.js-Anwendung mit drei Routen und einer nicht existierenden Benutzeroberfläche. Yaay. Es ist Zeit, es ein bisschen aufregender zu machen.
2. Hasura
Nichts bringt den Geist von JamStack besser zum Ausdruck als Hasura. Ich empfehle Ihnen, sich anzuschnallen, denn dank dieses Dienstes werden wir in wenigen Minuten ein vollständiges Backend mit GraphQL API erstellen.
Hasura tut Wunder, indem es Ihnen so wenig wie möglich von einer Datenbank, API und sogar etwas Backend-Logik verrät, obwohl es sicherlich einige Türen offen hält, wenn Sie daran interessiert sind, herumzuschnüffeln. Wir werden es für den Moment einfach halten, also lasst uns einfach auf den Punkt kommen.

Besuchen Sie https://cloud.hasura.io/ und loggen Sie sich mit dem Dienst Ihrer Wahl ein, dann entscheiden Sie sich für "Testen Sie eine kostenlose Datenbank mit Heroku". Heroku mag im JamStack-Universum ein wenig in Vergessenheit geraten sein, aber hier erfüllt es definitiv seinen Zweck. Sie müssen allerdings ein Konto erstellen (falls Sie noch keins haben).

Ganz am Ende des Prozesses klicken Sie auf "Projekt erstellen" und Sie sollten endlich im Hasura Dashboard landen.

Nachdem der Dienst erfolgreich initialisiert wurde, fahren Sie fort und gehen Sie direkt zur Seite "Data", wo wir uns endlich die Hände schmutzig machen können. Klicken Sie auf "Tabelle hinzufügen", wo wir einige Spalten zu unserer Tabelle und damit, dank Hasura und GraphQL-Magie, zu unserer API hinzufügen können. Dies kann sich ein wenig überwältigend anfühlen, wenn Sie noch nie mit einer Datenbank gearbeitet haben, aber keine Sorge, Hasura wird es so einfach wie möglich machen.

Lassen Sie uns damit beginnen, unserer Tabelle einen Namen zu geben (in meinem Fall: "Hunde") und eine Reihe von Feldern hinzufügen. Beachten Sie, dass Hasura UI eine intelligente Autovervollständigung bietet, die darauf basiert, welche Art von Datenbankfeld Sie gewählt haben (z.B. now()
für den Zeitstempel).
Ich schlage vor, den Abschnitt "Häufig verwendete Spalten" zu verwenden und id
mit der UUID-Voreinstellung zu nehmen, created_at
und updated_at
, wobei Sie damit nach Belieben herumspielen können. Der Rest der Felder ist Ihnen überlassen, aber ich werde mich an mein "Hunde"-Thema halten und name
hinzufügen, age
, bio
and image
. Machen Sie sich nicht zu viele Gedanken darüber, denn Sie können es später noch ändern.
Stellen Sie nur sicher, dass Sie "id" als Primärschlüssel Ihrer Tabelle wählen.

Dann gehen Sie zu unserer neu erstellten Tabelle und klicken auf die Registerkarte "Zeile einfügen", um sie mit einem ersten Datensatz zu füllen. Wenn Sie Felder mit vorgegebenen Standardwerten haben, werden diese von Anfang an verwendet, sodass ich mich in meinem Fall nur um "name", "age", "image" und "bio" kümmern muss.

Erledigt! Und ich meine wirklich fertig - das Einzige, was Sie jetzt auf der Seite von Hasura tun können, ist mit der GraphiQL-Schnittstelle herumzuspielen, um Ihre API abzufragen.

Mit zunehmender Erfahrung mit GraphQL-APIs werden Sie mehr und mehr mit dieser Ansicht vertraut werden: lernen Sie GraphiQL kennen. Dies ist Ihr interaktiver GraphQL-Spielplatz, von dem aus Sie auch ohne umfangreiche Kenntnisse der Sprache eine GraphQL-Abfrage erstellen können. Sie sollten in der Lage sein, auf Ihre Tabelle von der Seite "Explorer" aus zuzugreifen, genau dort, wo ich meine "Hunde" habe. Durch Anklicken der Kontrollkästchen können Sie der Abfrage automatisch ein Feld hinzufügen, ganz im Sinne des GraphQL-Credos: Man holt nur, was man braucht.

3. Next.js + Hasura
3.1 Umgebungsvariablen
Nun, gehen wir zurück zu unserer Next.js-Anwendung.
Um in Zukunft nicht damit belästigt zu werden, fügen wir zunächst die Hasura-Endpunkt-URL als Umgebungsvariable zu unserem Projekt hinzu. Glücklicherweise hat Next.js in dieser Hinsicht massive Verbesserungen in eine der letzten Versionen, so dass es so einfach ist wie:
.env
-Datei erstellenHinzufügen zu
.gitignore
Speichern Sie unsere URL dort und denken Sie daran, dass sie 1) der Namenskonvention „NEXT_PUBLIC_XYZ“ folgen muss, damit sie sowohl auf dem Client als auch auf dem Server zugänglich ist. 2). Kopieren Sie nicht das „https://“-Protokoll, da wir mit der URL flexibel sein wollen.
Daher sollte unsere .env
wie folgt aussehen:
3.2 Vom Server zum Client
Next.js glänzt am meisten, wenn man seine Fähigkeiten auf der Seite des Datenabrufs richtig nutzt. Das Framework bietet Ihnen eine Reihe von Methoden, die Sie auf pages/
Routenkomponenten ausführen können, die festlegen, wie dieser Teil der Anwendung aufgebaut und bedient wird. Wenn Sie sich zum Beispiel für getServerSideProps
- eine Funktion, die wie ein "Fenster" zum serverseitigen Bereich von Next.js funktioniert - diese gesamte Seite wird automatisch serverseitig gerendert.
Das perfekte Szenario für eine solche Seite wäre, wenn wir während des Builds die Anzahl und den Inhalt aller URLs unter dieser Subroute nicht kennen, da sie ständig hinzugefügt werden können. Denken Sie an eine grosse E-Commerce-Website, auf der jede Minute neue Produkte und Angebote hinzugefügt/entfernt werden können.
Unser Anwendungsfall ist einfacher - die Anzahl der Hunde im Tierheim wird sich nicht allzu sehr ändern, so dass wir in der Lage sein werden, sie statisch zu rendern. Das bedeutet, dass wir in Zukunft eher mit getInitialProps
oder getStaticProps
Methode arbeiten werden, aber um zu zeigen, dass sie sich in der Implementierung nicht allzu sehr unterscheiden, fügen wir hier kurz getServerSideProps
hinzu.
Hinweis: console.log
wird im Browser nicht angezeigt, aber...

...im Terminal, auf der Serverseite, ist es so.

Also lassen Sie uns eine fest kodierte "Scooby-Doo" Zeichenkette an unsere UI übergeben.

3.3 Apollo-Konfiguration
Während dieses Muster für reale Anwendungen völlig nutzlos ist, wird die Idee, die Daten von der Server-Seite an den Client zu übergeben, verwendet, sobald wir anfangen, sie von der API zu holen. Und dafür brauchen wir Apollo:
Apollo lässt sich am besten als Brücke zwischen dem UI-Framework (diese Rolle wird in unserem Stack von React/Next.js übernommen) und GraphQL beschreiben. Dieser Koloss von einer Bibliothek bietet eine Vielzahl von Funktionen sowohl für die Erstellung von GraphQL-Servern, als auch für das Abrufen von Daten aus einer bestehenden GraphQL-API.
Es gibt keinen goldenen Standard für das Abrufen von Daten (serverseitig vs. clientseitig), da es in der Praxis meist auf eine Kombination aus beidem hinausläuft. Deshalb möchte ich Ihnen zunächst zeigen, wie wir das im Browser mit Hilfe des useQuery
-Hooks machen können. Um dies zu ermöglichen, müssen wir zunächst unseren ApolloClient
initialisieren und über die gesamte Anwendung verteilen. Dankenswerterweise hat Next.js genau dafür eine Komponente namens pages/_app.tsx
. Sie können es sich als einen Wrapper vorstellen, der jede Seite umhüllt.
Kümmern wir uns zuerst um unseren ApolloClient:
Wie wir sehen können, braucht es nicht viel, um zu funktionieren: nur die URL unserer Hasura Cloud GraphQL API (gespeichert in einer env var) und eine neue Instanz von InMemoryCache()
, die das Caching der Anfragen für uns übernimmt. Dann können wir es unseren Routen wie folgt zur Verfügung stellen:
3.4 useFetch
And dann auf unsere pages/dogs
, wobei wir, wie im ursprünglichen Plan angenommen, alle Hunde abrufen und einige grundlegende Informationen über sie anzeigen wollen. Hier kommt uns die GraphiQL-Spielwiese zu Hilfe - wir können unsere Abfrage dort spezifizieren und sie einfach in unseren Editor kopieren, sobald sie fertig ist. Um sie für Apollo lesbar zu machen, müssen wir sie allerdings mit einer gql
Funktion verpacken:
Dann bringen wir den bereits angekündigten Hook namens useQuery
ein. Ausgestattet mit der GraphQL-Serverkonfiguration ist es dank der Arbeit, die wir in der _app.tsx
geleistet haben, nun in der Lage, ohne viele weitere Parameter zu arbeiten. Das einzige, was wir ihm übergeben müssen, ist unsere Anfrage, in meinem Fall GET_DOGS
, und der Antworttyp (DogsResponseData
). Dieser Hook gibt drei Dinge zurück, die bei jedem, der schon einmal eine API abgefragt hat, eine Augenbraue hochziehen sollten: loading
, error
and data
.
Das Erste ist ein Boolean - wenn es wahr ist, sollten wir eine Art von Ladekomponente anzeigen. Das zweite ist eine Instanz von ApolloError
- wenn es nicht nullish ist, bedeutet es, dass etwas schief gelaufen ist und der/die Benutzer:in eine entsprechende Rückmeldung erhalten sollte. Wenn beides false ist, bedeutet das, dass wir die Daten endlich auspacken und in der UI anzeigen können:
Nach diesen Änderungen sieht die gesamte Komponente wie folgt aus:
Meiner Meinung nach sieht das schon aufgeräumt genug aus, aber wenn wir ganz Marie Kondo werden wollen, können wir auch separate Dateien für unsere queries
und types
erstellen und werfen unsere Abfrage GET_DOGS
und geben dort Dog
ein.
3.5 Daten auf der Server-Seite abrufen
Hier kommt der letzte Teil der Implementierung, den wir in diesem Blog-Post machen werden: die API auf der Server-Seite abfragen. Dafür brauchen wir ein paar grössere Geschütze: apolloClient.js
und withApollo.jsx
Wrapper. Fairerweise muss man sagen, dass ich sie mir nicht selbst ausgedacht habe - sie werden in der offiziellen Hasura & Apollo & Next.js Implementierungsdokumentation hier beschrieben.
Unglücklicherweise geht die Dokumentation davon aus, dass wir eine Authentifizierung (auth0) in unserer Anwendung haben wollen, was im Moment nicht nötig ist, also habe ich mich entschlossen, es in TypeScript zu übersetzen, es ein wenig aufzuräumen und nur das zu belassen, was für unsere einfache Demo notwendig ist.
Bitte beachten Sie, dass wir hier unsere API-URL-Umgebungsvariable (in meinem Fall das NEXT_PUBLIC_API_HOST
) verwenden:
TypeScript-Version des withApollo
-Wrappers war auch nirgends in der offiziellen Dokumentation zu finden, aber glücklicherweise konnte ich ihn in einem sehr hilfreicher Kommentar von samuelcastro zu einem von Next.js GitHub Problem finden.
Wenn wir das erledigt haben, können wir zu unserer _app.tsx
und die Initialisierung des ApolloClient
dort loswerden, da wir dies von nun an auf Seitenebene tun werden. Wir müssen nicht die ganze Datei löschen, da wir sie wahrscheinlich irgendwann noch brauchen werden. Nach der Bereinigung sollte die Datei etwa so aussehen:
Der nächste Schritt besteht darin, die Logik des Client-Abrufs durch ihre serverseitige Entsprechung zu ersetzen. Wir können den Dog
Typ und die Abfrage intakt lassen, aber wir müssen definitiv unseren withApollo
mit ssr
auf true
und umhüllen die Komponente damit.
Okay, jetzt wird es ein bisschen ernster, aber keine Sorge, wir werden es aufschlüsseln:
Zuerst lassen Sie uns einen Blick auf die getInitialProps
Funktion werfen, auf die wir von unserer Dog
Komponente zugreifen. Warum können wir das überhaupt tun, wenn wir diese Komponente selbst geschrieben haben und uns nicht an eine solche Funktion erinnern können? Die Erklärung ist einfach: es ist Next.js und seine Zaubertricks. Wie ich bereits erwähnt habe, haben unsere Routen im Ordner pages/
einen Data-Fetching Superpowers und dies ist einer von ihnen.
Um sie richtig zu nutzen, müssen wir TypeScript glücklich machen, indem wir den Typ unserer Komponente Dogs
von ändern:
zu
was Sinn macht, weil getInitialProps
nur von der Next.js-Seite aus zugänglich ist, nicht von einer regulären funktionalen React-Komponente. TypeScript weiss jedoch nicht, dass es sich um eine Next.js-Seite handelt, auch wenn sie sich im Verzeichnis pages/
befindet.
Zurück zur Funktion selbst: es handelt sich um eine normale asynchrone Funktion, die auf der Server-Seite ausgeführt wird und Werte zurückgibt, auf die wir auf der Client-Seite zugreifen können. Die Parameter bestehen aus einem Next.js-Kontextobjekt, genannt NextPageContext
, das wir mit unserem ApolloClient
erweitern. Daher die Definition für den ServerSideProps
:
Warum weiss ich, dass der ApolloClient diesen ganz bestimmten Typ hat? Ich habe ihn auf die einfachste Art und Weise erworben - ich habe ihn von der Typdefinition eines Rückgabewerts einer createApolloClient
-Funktion kopiert, die wir in unserer lib/apolloClient.js
, auch wenn die Datei im einfachen .js-Format vorliegt. Gesegnet seist du TypeScript, gesegnet seist du VSCode.

Dann ist die eigentliche Anfrage recht einfach, wir müssen nur daran denken, den Antworttyp an die Abfragemethode von ApolloClient zu übergeben:
Der einzige Unterschied ist, dass wir tatsächlich await
abwarten und sich nicht mit dem loading
beschäftigen. Sobald es angekommen ist, graben wir die tatsächlichen Hunde aus und kehren zu unserer Dogs
-Komponente zurück, wobei wir ihr mitteilen, dass wir vorher ein Array von Objekten vom Typ Dog
übergeben werden:
In seiner ganzen Pracht sieht pages/dogs.tsx
mit server-seitigem Datenabruf so aus:
Und das war's! Das Ergebnis ist im Grunde dasselbe, der einzige Unterschied ist, dass wir das loading
nicht jedes Mal für einen Sekundenbruchteil sehen, wenn wir die Seite aufrufen. Die Daten werden gnädigerweise auf der Serverseite abgerufen und in der Komponente gerendert, als ob sie schon immer da gewesen wären.
5. Deploy
Seien Sie nicht schüchtern! Diese hochmoderne Anwendung verdient es auf jeden Fall, dass man mit ihr prahlt, also lassen Sie uns damit prahlen. Für die Bereitstellung werden wir uns ein letztes Tool schnappen, das diesen Prozess extrem angenehm machen wird: Vercel. Installieren wir seine CLI global auf unserem Rechner:
und führen Sie diesen kleinen Befehl im Projektverzeichnis aus, um es in der Cloud bereitzustellen:
Ich möchte Ihnen die Freude an der Interaktion mit Vercel nicht vorenthalten, also keine Spoiler, wie reibungslos das Ganze funktioniert. Nachdem Sie alles erfolgreich eingerichtet haben, müssen Sie noch eine letzte Sache zu Ihrer Produktionsumgebung hinzufügen: Ihre Umgebungsvariablen. Das geht ganz einfach, indem Sie im Projekt auf „Einstellungen“ und dann auf die Registerkarte „Umgebungsvariablen“ gehen und sie dort einfach einfügen.

Boom! Das war's eigentlich schon. Sie haben soeben eine vollständige JamStack-Anwendung mit Routen, TypeScript, CI/CD, GraphQL-API und SSR erstellt, Sie Verrückter! Aber die Show muss auf jeden Fall weitergehen - in den nächsten Blog-Beiträgen werden wir unserem Hundeheim weitere CRUD-Operationen hinzufügen, unsere Flügel mit GraphQL & Hasura ausbreiten, komplexere Datenabrufszenarien angehen und wer weiss, vielleicht sogar eine einfache Benutzeroberfläche bauen. Vielen Dank fürs Vorbeischauen und bis zum nächsten Beitrag!
✍️
ÜBER DEN AUTOR

Adrian Pilarczyk
Senior Backend-Entwickler
Bester Freund von React und TypeScript. Engagierter Medienkonsument: Podcast-Kopf, Kinobesucher, Bücherwurm, immer aufnahmefähig. Liebhaber von MMA & BJJ 🥊.