diff --git a/.vscode/settings.json b/.vscode/settings.json index cc4ccbf..83f73a3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,6 @@ "landing", "build", "knowledge-base" - ] + ], + "typescript.tsdk": "node_modules/typescript/lib" } \ No newline at end of file diff --git a/src/components/slides/node-backend/fastify.astro b/src/components/slides/node-backend/fastify.astro new file mode 100644 index 0000000..6bace6f --- /dev/null +++ b/src/components/slides/node-backend/fastify.astro @@ -0,0 +1,19 @@ +
+
+

Bessere Webserver mit Fastify

+
+ +
+

Wir haben in den vorangegenangenen Folien gesehen, wie man einen einfachen Web-Server in NodeJS erstellt.

+

Moderne Features wie Routing-Logik, Logging, Error-Handling und weitere Features waren nicht mit inbegriffen.

+

Wir wollen das auch nicht selber schreiben. Hierfür wurde das Rad unzählige male für verschiedenste Problemstellungen neu Entwickelt.

+
+ +
+

Eines dieser vielen Räder schauen wir uns genauer an: Fastify

+

Fastify ist ein modernes Web-Framework um seinen eigenen Web-Server zu bauen. Es bietet die vorher erwähnten Features und hat darüber hinaus noch mehr zu bieten.

+

Das wichtigste aus meiner Sicht: Eine solide TypeScript Unterstützung.

+
+ + +
\ No newline at end of file diff --git a/src/components/slides/node-backend/index.astro b/src/components/slides/node-backend/index.astro new file mode 100644 index 0000000..1e9f19e --- /dev/null +++ b/src/components/slides/node-backend/index.astro @@ -0,0 +1,13 @@ +--- +import Title from "./title.astro"; +import Plain from "./plain.astro"; +import Protocols from './protocols.astro'; +import Fastify from "./fastify.astro"; +--- + +
+ + <Plain /> + <Protocols /> + <Fastify /> +</div> \ No newline at end of file diff --git a/src/components/slides/node-backend/plain.astro b/src/components/slides/node-backend/plain.astro new file mode 100644 index 0000000..193ba18 --- /dev/null +++ b/src/components/slides/node-backend/plain.astro @@ -0,0 +1,116 @@ +<section> + <section> + <p>Wir beginnen nun damit, einen (bzw. mehrere) Server mit JavaScript auf NodeJS zu implementieren.</p> + <p>NodeJS ist im Vergleich zur Umgebung im Browser anders aufgebaut. Wir haben zum Beispiel kein <code>document</code> auf das wir beispielsweise zugreifen könnten.</p> + </section> + + <section> + <p>Dafür haben wir nun Zugriff auf die gesamte NodeJS-API um mit dem Betriebssystem zu interagieren (Dateizugriffe, Netzwerk-Ports öffnen und so weiter).</p> + <p>Wenn Node installiert ist, können wir eine JavaScript Datei mit <code>node name-der-datei.js</code> ausführen.</p> + </section> + + <section> + <p>Legen wir nun eine erste Datei <code>server.js</code> an:</p> + <pre class="js"><code data-trim data-line-numbers="1|3-5" is:raw> + const http = require("node:http"); + + http.createServer(function(req, res) { + res.end(); + }).listen(8080); + + console.log("Server listening on port 8080!"); + </code></pre> + </section> + + <section> + <p>Funktionalitäten in NodeJS sind in <strong>Modulen</strong> geschrieben. Wir können auf diese jederzeit zugreifen.</p> + <p>Je nachdem wie das Projekt aufgebaut ist, müssen wir auf diese Module anders zugreifen.</p> + <p>In nicht näher konfigurierten Projekten müssen wir mittels <code>require("modulname")</code> auf diese Sachen zurgeifen.</p> + </section> + + <section> + <p>In moderneren Projekten, benutzen wir die neuere Modul-Syntax die mittels den keywords <code>import something from 'modul';</code> aufgerufen wird.</p> + <p>Das aktuelle Setup macht nicht viel... Senden wir mal etwas an den Sender zurück!</p> + </section> + + <section> + <p>Wir nutzen <code>res.write()</code> um Inhalte zum Client zurück zu senden</p> + <pre class="js"><code data-trim data-line-numbers="2" is:raw> + http.createServer(function(req, res) { + res.write("Hallo vom Server!"); + res.end(); + }).listen(8080); + </code></pre> + </section> + + <section> + <h3>Request & Response</h3> + </section> + + <section> + <p>Wenn der Server startet, wird bei jedem Request zum Server die Callback-Funktion ausgeführt.</p> + <p>Diese Funktion erhält zum einen ein Request-Objekt und zum zweiten ein Response-Objekt.</p> + </section> + + <section> + <p>Mit dem Request-Objekt können wir alle Informationen aus der vom Client gesendeten Anfrage extrahieren. Das Objekt ist (ähnlich zum Reponse-Objekt) recht komplex gestaltet.</p> + <p>Im Request finden wir die URL (den Pfad) über den wir die Anfrage erhalten haben, ggf. den Body, welche Methode, und mehr.</p> + </section> + + <section> + <p>Das Response-Objekt beinhaltet Funktionalität um Daten zurück zu senden. Wichtig ist dabei zu wissen das wir mit einem NodeJS-Stream Objekt interagieren.</p> + <p>Streams sind Lesbar, Schreibbar oder beides. Sie dienen dazu mit verschiedenen Dingen zu interagieren (wie zum Beispiel Netzwerk-Streams, Interkation mit Dateien und mehr).</p> + </section> + + <section> + <p>Für uns wichtig ist erstmal der Umstand, das wir in das response-Objekt mittels <code>.write()</code> Daten in den Stream hinein schreiben können, und dass wir mit <code>.end()</code> den Stream schließen können (und damit ultimativ den Request "beenden" oder schließen).</p> + </section> + + <section> + <p>Geben wir ein paar Infos zum <em>testen</em> zurück.</p> + <pre class="js"><code data-trim data-line-numbers="3-4" is:raw> + http.createServer(function(req, res) { + res.write("Hallo vom Server!<br />"); + res.write(`Request unter dem Pfad ${req.url} aufgerufen. + Verwendete Methode: ${req.method}`); + res.end(); + }).listen(8080); + </code></pre> + </section> + + <section> + <p>Nun erhalten wir ein paar Informationen im Browser (Pfad + Methode). Aber offensichtlich denkt der Browser nicht, dass wir hier mit HTML arbeiten..</p> + <p>Wir arbeiten auch nicht wirklich mit HTML, aber wir können dem Browser mitteilen, dass das was wir versenden HTML ist und vom Browser entsprechend interpretiert werden soll.</p> + </section> + + <section> + <pre class="js"><code data-trim data-line-numbers="2" is:raw> + http.createServer(function(req, res) { + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.write("Hallo vom Server!<br />"); + res.write(`Request unter dem Pfad ${req.url} aufgerufen. + Verwendete Methode: ${req.method}`); + res.end(); + }).listen(8080); + </code></pre> + </section> + + <section> + <p>Damit sollte der Browser die Empfangenen Daten als HTML erkennen und sein möglichstes Versuchen um dieses korrekt zu rendern (also ohne, dass wir extra den Kompletten Rahmen mitsenden müssten.)</p> + </section> + + <section> + <p>Wenn wir nun mehr daraus machen wollen, müssten wir ein paar Dinge implementieren:</p> + <ul> + <li>Routing</li> + <li>Header-Logik</li> + <li>Middleware-Systeme</li> + <li>Und mehr...</li> + </ul> + </section> + + <section> + <p>Aber bevor wir uns damit auseinander setzen, verwenden wir lieber bereits existierende Frameworks die uns all diesen Aufwand ersparen.</p> + <p>Bevor wir aber dazu kommen, sehen wir uns die darunter liegenden Protokolle an, die wir hier verwenden.</p> + </section> +</section> \ No newline at end of file diff --git a/src/components/slides/node-backend/protocols.astro b/src/components/slides/node-backend/protocols.astro new file mode 100644 index 0000000..68beed6 --- /dev/null +++ b/src/components/slides/node-backend/protocols.astro @@ -0,0 +1,162 @@ +<section> + <section> + <h2>Protokolle</h2> + </section> + + <section> + <p>Wir betrachten nun in den Nachfolgenden Slides was passiert wenn wir eine URL im Browser angeben bis zu dem Zeitpunkt an dem wir alle Daten empfangen haben.</p> + </section> + + <section> + <h3>DNS</h3> + </section> + + <section> + <p>Wenn wir eine URL wie "google.de" haben, weiß unser PC nicht, wohin der Request gesendet werden muss. Dazu benötigt der PC die IP-Adresse des Ziels.</p> + <p>IP-Adressen sind heutzutage entweder in der Version 4 oder Version 6 vorhanden. Version 6 wurde primär dazu erfunden, weil es keine Verfügbaren IPv4 Adressen mehr gab.</p> + </section> + + <section> + <p>Um einen Namen wie "google.de" in eine für den Computer / das Netzwerk interpretierbare Adresse umzuwandeln, frägt der Computer bei einem DNS-Server nach.</p> + <p>Der Namens-Server gibt uns eine IP-Adresse zu der dann der Request gesendet werden kann.</p> + </section> + + <section> + <p>Die Info, unter welcher IP der Namensserver zu finden ist, erhalten wir durch unseren Internet-Service-Provider (Über den Router des Providers).</p> + <p>Es gibt ein paar Schritte die bei einem DNS-Lookup geschehen:</p> + </section> + + <section> + <h4>Anfrage beim "Recursive Resolver"</h4> + </section> + + <section> + <p>Die IP vom DNS-Server die wir "haben", ist die eines "DNS Recursive Resolvers". Dieser ist der "Einstiegspunkt" in der Suche eines Namenseintrages.</p> + <p>DNS-Server bestehen nicht nur aus einzelnen Servern sondern sind einer Verkettung von mehreren Namens-Servern die jeweils einen kleineren Teil des Namens-Raums kennen.</p> + </section> + + <section> + <h4>Anfrage beim Root-Server</h4> + </section> + + <section> + <p>Der DNS-Root-Server ist die erste Übersetzungs-Ebene im DNS-System.</p> + <p>Der Root-Server kennt dabei den "nächsten" Ansprechpartner (Server), der die Adresse kennt.</p> + <p>Im Normalfall ist dies ein Top-Level-DNS-Server</p> + </section> + + <section> + <h4>Anfrage beim TLD-DNS-Server</h4> + </section> + + <section> + <p>Der Recursive Resolver frägt nun beim TLD-DNS-Server nach der IP des gesuchten Ziels.</p> + <p>Überlicherweise erhält der Resolver die IP des <strong>Authorative Nameserver</strong>.</p> + </section> + + <section> + <h4>Anfrage beim Authorative Nameserver</h4> + </section> + + <section> + <p>Der Authorative Nameserver hat die Einträge der gesuchten Domains (Name zu IP-Mapping)</p> + <p>Der Recursive Resolver kann uns nun mit der gesuchten IP Antworten.</p> + </section> + + <section> + <h3>http</h3> + </section> + + <section> + <p>Jeder Gängige Web-Request wird über das HTTP-Protokol versendet.</p> + <p>Über die Jahre hat sich das HTTP-1 Protokol entwickelt (HTTP2 und HTTP3). Der Inhalt eines jeden Requests ist aber zunächst gleich/ähnlich.</p> + </section> + + <section> + <p>Ein HTTP-Request besteht aus mehreren Informationen:</p> + <ol> + <li>Versions-Information (HTTP)</li> + <li>Ziel-URL</li> + <li>HTTP-Methode</li> + <li>Request-Header</li> + <li>(optionaler) Body</li> + </ol> + </section> + + <section> + <h4>HTTP-Methode</h4> + </section> + + <section> + <p>Die HTTP-Methode definiert die Aktion die wir auf einer URL (auch genannt Resource) ausführen wollen.</p> + <p>Der Browser sendet im ohne Information "by default" ein GET bei allen Requests</p> + </section> + + <section> + <ul> + <li><strong>GET</strong> um Inhalte zu erhalten</li> + <li><strong>POST</strong> um Inhalte anzulegen</li> + <li><strong>PUT</strong> um Inhalte zu modifizieren</li> + <li><strong>DELETE</strong> um Inhalte zu löschen</li> + </ul> + </section> + + <section> + <p>Es gibt noch weitere Methoden wie OPTIONS, aber diese werden seltener direkt in der Webentwicklung genutzt.</p> + </section> + + <section> + <h4>Headers</h4> + </section> + + <section> + <p>Header im HTTP-Request enthalten zusätzliche Informationen als Key-Value-Paare.</p> + <p>Header können entweder durch Code gesetzt werden (also durch den Entwickler) als auch durch den User-Agent (Web-Browser)</p> + </section> + + <section> + <p>Beispielhafte Inhalte</p> + <ul> + <li><strong>accept</strong>: Welche Datentypen als Antwort akzeptiert werden</li> + <li><strong>Auhtorization</strong>: Optionale Angabe von Informationen zum verifizieren von Nutzern.</li> + <li><strong>User-Agent</strong>: Informationen zum User-Agent (Browser zum Beispiel)</li> + <li><strong>Cache-Control</strong>: Informationen wie Inhalte gecached werden sollen</li> + <li><strong>Cookie</strong></li> + </ul> + </section> + + <section> + <h4>Body</h4> + </section> + + <section> + <p>Im Body eines Requests stehen die zu übertragenden Informationen der jeweiligen Seite.</p> + <p>Der Body kann bei GET-Requests von der Sendenden Partei nicht gesetzt werden.</p> + <p>Im Body befindet sich bei einer Anfrage mittels Post zum Beispiel die Information für die zu anlegende Resource.</p> + </section> + + <section> + <h4>HTTP-Responses</h4> + </section> + + <section> + <p>Sobald / Während der Bearbeitung kann der Server in einer Response einen StatusCode festlegen, die dem Client mitteilen soll, wie der Status zur Bearbeitung der Anfrage ist.</p> + <p>Diese Responses sind eine Zahl im Bereich zwischen 100 und 599. Wobei jede "100-er" Kategorie einen anderen Allgemeinen Zustand definiert:</p> + </section> + + <section> + <ol> + <li><strong>1xx</strong> Information</li> + <li><strong>2xx</strong> Success</li> + <li><strong>3xx</strong> Redirect</li> + <li><strong>4xx</strong> Client Error</li> + <li><strong>5xx</strong> Server Error</li> + </ol> + <p>Eine Ausführliche Erklärung (mit Katzen) ist <a href="https://http.cat/" rel="noopener noreferrer">hier</a> zu finden</p> + </section> + + <!-- TODO: TCP/IP --> + <!-- <section> + <h3>TCP/UDP</h3> + </section> --> +</section> \ No newline at end of file diff --git a/src/components/slides/node-backend/title.astro b/src/components/slides/node-backend/title.astro new file mode 100644 index 0000000..5cce3aa --- /dev/null +++ b/src/components/slides/node-backend/title.astro @@ -0,0 +1,3 @@ +<section> + <h1>Backend-Entwicklung mit NodeJS (und Fastify)</h1> +</section> \ No newline at end of file diff --git a/src/pages/slides/flexi-pool/02-backend-development.astro b/src/pages/slides/flexi-pool/02-backend-development.astro new file mode 100644 index 0000000..09fcee6 --- /dev/null +++ b/src/pages/slides/flexi-pool/02-backend-development.astro @@ -0,0 +1,8 @@ +--- +import Reveal from "../../../layouts/Reveal.astro"; +import Slides from "../../../components/slides/node-backend/index.astro"; +--- + +<Reveal title="Backend Entwicklung mit NodeJS"> + <Slides /> +</Reveal> \ No newline at end of file