Diese Datei ist in Markdown geschrieben und kann mit
<Strg><Shift>vin Visual Studio Code leicht gelesen werden.Näheres zu Markdown gibt es z.B. bei Markdown Guide
Nur in den ersten beiden Vorlesungswochen kann es Unterstützung bei Installationsproblemen geben.
- Hinweise zum Programmierbeispiel
- Inhalt
- Vorbereitung von Prisma für Nest
- Download- und ggf. Upload Geschwindigkeit
- Vorbereitung der Installation
- ES Modules (= ESM)
- Node Best Practices
- Lokaler Appserver mit Nest und dem Watch-Modus
- Postman: Desktop-Anwendung und Extension für VS Code
- Tests aufrufen
- Docker-Image und Docker Compose
- Statische Codeanalyse und Formattierer
- Sicherheitslücken
- OpenAPI
- AsciiDoctor und PlantUML
- TypeDoc
- Continuous Integration mit Jenkins
- Visual Studio Code
- Empfohlene Code-Konventionen
Nachdem das Prisma-Schema in der Datei prisma/schema.prisma erstellt wurde,
sind für das Nest-basierte Projekt folgende Anpassungen notwendig:
- In
tsconfig.json, weil beim direkten Arbeiten mit Node das Feature Type Stripping genutzt wurde, d.h. Node wurde aufgerufen und die Typen von TypeScript wurden zur Laufzeit einfach weggelassen. Nest verwendet dagegen übersetzten Code, d.h. JavaScript.- bei der Option
emitDecoratorMetadataden Kommentar entfernen - die Option
noEmitauskommentieren - die Option
allowImportingTsExtensionsauskommentieren
- bei der Option
- Der Prisma-Client muss deshalb auch neu generiert werden, d.h.
- das Verzeichnis
src\generatedwird gelöscht und pnpx prisma generatewird in der PowerShell aufgerufen.
- das Verzeichnis
- Die bisherigen Beispieldateien
beispiele.mtsundbeispiele-write.mtsfür den "alten" Prisma-Client können deshalb nicht mehr funktionieren, weshalb man sie am einfachsten aus dem Projekt löscht.
In einem Webbrowser kann man z.B. mit der URL https://speed.cloudflare.com die
Download- und die Upload-Geschwindigkeit testen.
Alternativ kann man durch das Kommando fast in einer Powershell die aktuelle
Download-Geschwindigkeit ermitteln. Mit der zusätzlichen Option --upload kann
zusätzlich die aktuelle Upload-Geschwindigkeit ermittelt werden.
-
Das Beispiel nicht in einem Pfad mit Leerzeichen installieren. Viele Javascript-Bibliotheken werden unter Linux entwickelt und dort benutzt man keine Leerzeichen in Pfaden. Ebenso würde ich das Beispiel nicht auf dem Desktop auspacken bzw. installieren.
-
Bei GitHub oder GitLab registrieren, falls man dort noch nicht registriert ist.
ESM ist die gängige Abkürzung für ES Modules, so dass man import und
export statt require() aus CommonJS verwenden kann. Die Unterstützung von
ESM wurde in Node ab Version 12 begonnen. Außerdem ist es wichtig, das man beim
Umstieg auf ESM auch die Unterstützung in ts-node und ts-jest beachtet.
Wenn man ESM verwendet, muss man die eigenen Module z.B. folgendermaßen importieren:
import { myFunc } from './foo.js';
import { myClass } from './bar/index.js';Außerdem gibt es ab Node 17.1 das Node Protocol für den Import von Builtin Modules, z.B.:
import { resolve } from 'node:path';Gute Literatur zu ESM gibt es bei:
- https://nodejs.org/api/esm.html#esm_node_imports
- https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
- https://docs.joshuatz.com/cheatsheets/node-and-npm/node-esm
- https://www.typescriptlang.org/docs/handbook/esm-node.html
- TypeStrong/ts-node#1007
Unterstützung für ESM ist notwendig in:
- Node
- TypeScript
- ts-node
- ts-jest: versteht noch nicht die Datei-Endung
.mtsund beim Import.mjs - VS Code
- Node innerhalb von Jenkins
Sehr empfehlenswert ist https://github.com/goldbergyoni/nodebestpractices
Durch pnpm run dev wird der Appserver im Watch-Modus für die
Entwicklung gestartet, d.h. bei Code-Änderungen wird der Server automatisch
neu gestartet.
Beim Starten des Appservers wird außerdem mit TypeORM auf die Datenbank
zugegriffen. Der Benutzername und das Passwort sind in der Datei
src\config\db.ts auf admin und p voreingestellt. Durch die Property
db.populate in src\config\resources\buch.yml wird festgelegt, ob die
(Test-) DB buch neu geladen wird.
Mit der Desktop-Applikation Postman wie auch mit der Erweiterung Postman für VS Code kann man u.a. REST-, GraphQL und gRPC-Schnittstellen interaktiv testen.
Zunächst muss man sich bei https://www.postman.com registrieren und kann danach
die Desktop-Application Postman von https://www.postman.com/downloads
herunterladen und installieren. Die Installation erfolgt dabei im Verzeichnis
${LOCALAPPDATA}\Postman\app-VERSION, z.B. C:\Users\MeineKennung\AppData\Local\Postman\app-VERSION.
Über die Desktop-Applikation legt man sich folgendermaßen einen Workspace an:
- Den Menüpunkt Workspaces anklicken
- Im Drop-Down Menü den Button Create Workspace anklicken
- Danach den Button Next anklicken
- Im Eingabefeld Name
buchund im Eingabefeld Summary z.B.REST- und GraphQL-Requests für den Appserver. - Abschließend den Button Create anklicken.
Zunächst legt man ein Environment mit Variablen an. Dazu wählt man am
linken Rand den Menüpunkt Environments, klickt auf den Button Import
und wählt aus dem Verzeichnis .extras\postman die Datei buch.postman_environment.json
aus. Jetzt hat man die Umgebung buch mit der Variablen base_url und dem
Wert https://localhost:3000 angelegt.
Im Environment buch muss man die Variable client_secret auf den Wert setzen,
der in Keycloak beim Realm acme in Clients > buch-client > Credentials
bei Client Secret steht.
Als nächstes wählt man den Menüpunkt Collections aus und importiert der Reihe
nach Collections aus dem Verzeichnis .extras\postman, indem man den Button
Import anklickt. Collections sind zusammengehörige Gruppierungen von Requests
und können zur besseren Strukturierung in Folder unterteilt werden.
Beispielsweise gibt es die Collection REST mit untergeordneten Folder, wie
z.B. Suche mit ID und Neuanlegen. Im Folder Suche mit ID gibt es dann z.B.
den Eintrag GET vorhandene ID 1, um einen GET-Request mit dem Pfadparameter
:id und dem Wert 1 abzusetzen.
Eine neue Collection legt man mit dem Button + an und einen untergeordneten Folder mit dem Overflow-Menü sowie dem Menüpunkt Add folder.
Im Overflow-Menü eines Folders oder einer Collection kann man durch den Menüpunkt Add request einen neuen Eintrag für Requests erstellen, wobei man dann z.B. folgendes festlegt:
- Bezeichnung des Eintrags
- GET, POST, PUT, PATCH, DELETE
- URL mit ggf. Pfadparameter, z.B. :id
- Im Karteireiter Params sieht man dann die Pfadparameter und kann auch Query-Parameter spezifizieren.
- Im Karteireiter Headers sieht man voreingestellte Request-Header und kann
auch zusätzliche eintragen, z.B. den Header
Content-Typeund als zugehörigen Wertapplication/hal+json. - Im Karteireiter Body kann man z.B. JSON-Daten für einen POST-Request oder Daten für GraphQL-Queries oder -Mutations eintragen. Dazu wählt man dann unterhalb von Body den Radiobutton raw mit JSON aus, wenn man einen POST- oder PUT-Request spezifiziert bzw. den Radiobutton GraphQL für Queries oder Mutations aus.
- Wenn man GraphQL-Requests spezifiziert, d.h. im Request-Body GraphQL festlegt, dann lädt Postman aufgrund der Request-URL das zugehörige GraphQL-Schema herunter, falls man die Vorbelegung Auto-fetch beibehält. Dadurch hat man Autovervollständigen beim Formulieren von Queries und Mutations.
Beachte: Wenn man gebündelte Requests von Collections oder Folders abschickt, hat man bis zu 50 "Runs" pro Monat frei.
Um bei der URL für die diversen Requests nicht ständig wiederholen zu müssen,
kann man in einer Collection auch Variable definieren, indem man die Collection
auswählt und dann den Karteireiter Variables, z.B. rest_url als Variablenname
und https://localhost:3000/rest als zugehöriger Wert.
Wenn ein Request eine URL adressiert, für die man einen Token benötigt, so muss
ein solcher Token vor dem Abschicken des Requests ermittelt werden. Dazu trägt
man bei der Collection, beim Folder oder beim konkreten Request im Karteireiter
Pre-request Script ein JavaScript ein, mit dem man vorab einen (Hilfs-) Request
senden kann, dessen Response dann einen Token liefert. Der Request wird mit
pm.sendRequest({...}, myCallback) abgeschickt.
Falls der Token im Response-Body in einem JSON-Datensatz z.B. in der Property
token empfangen wird, kann man den Token in z.B. einer Variablen in der
Collection puffern. Dazu liest man im Callback den Token durch res.json().token
aus dem Response-Body aus und puffert ihn z.B. in einer Collection-Variablen TOKEN.
Das ergibt insgesamt die Anweisung: pm.collectionVariables.set('TOKEN', res.json().token).
Unter dieser Voraussetzung kann man dann im Karteireiter Authorization bei der
Collection, beim Folder oder beim Request als Type die Option Bearer Token
auswählen und als Wert {{TOKEN}} eintragen. Dadurch wird der Request-Header
Authorization mit dem Wert Bearer <Aktueller_Token> generiert.
Wenn man Requests einzeln oder komplett für einen Folder oder eine Collection abschickt, dann kann man in Postman den zugehörigen Response zu jedem Request überprüfen. Dazu implementiert man ein JavaScript-Skript im Karteireiter Tests. Zur Überprüfung von z.B. Statuscode, Response-Header oder Response-Body stellt Postman die Chai Assertion Library mit expect bereit. Details zu Chai findet man bei https://www.chaijs.com/api/bdd.
Seit Mai 2023 gibt es Postman auch als Erweiterung für VS Code. Damit kann man zwar (noch) nicht Workspaces, Collections, Folders und Requests anlegen, aber Requests abschicken, ohne dass man VS Code als Arbeitsumgebung verlassen muss.
Auch von der PowerShell können Requests an die REST-Schnittstelle abgeschickt werden:
# GET-Request an die REST-Schnittstelle
Invoke-WebRequest https://localhost:3000/rest/1 -SslProtocol Tls13 -SkipCertificateCheckFolgende Voraussetzungen müssen oder sollten erfüllt sein:
- Der DB-Server muss gestartet sein.
- Der Mailserver muss gestartet sein.
- Der Appserver muss gestartet sein.
Nun kann man die Tests folgendermaßen in einer Powershell aufrufen. Dabei wird
beim Skript test in package.json die Property log.default auf true
gesetzt, um nicht zu detailliert zu protokollieren bzw. damit die Log-Ausgabe
übersichtlich bleibt.
pnpm tBei der Fehlersuche ist es ratsam, nur eine einzelnen Testdatei oder sogar geziehlt eine Test-Funktion aufzurufen, z.B.:
# Filter für den Namen der Testdatei
pnpm vitest GET-id
# Test-Funktion an einer bestimmten Zeile in der Testdatei
pnpm vitest test/integration/rest/GET-id.test.mts:47Für ein minimales Basis-Image gibt es z.B. folgende Alternativen:
- Debian Trixie slim
- ca. 250 MB
- Trixie ist der Codename für Debian 13
- mit Node 22
- Alpine
- ca. 50 MB
- C-Bibliothek musl statt von GNU
- ash als Shell
- apk ("Alpine Package Keeper") als Package-Manager
- mit Node 22
Durch eine Default-Datei Dockerfile kann man ein Docker-Image erstellen und
durch ein Multi-stage Build optimieren. Eine weitverbreitete Namenskonvention
für ein Docker-Image ist <registry-name>/<username>/<image-name>:<image-tag>.
Ob das Dockerfile gemäß Best Practices (https://docs.docker.com/develop/develop-images/dockerfile_best-practices)
erstellt wurde, kann man mit Hadolint überprüfen.
# Debian Trixie (13) slim
Get-Content Dockerfile | docker run --rm --interactive hadolint/hadolint:v2.13.1-beta4-debian
docker build --tag juergenzimmermann/buch:2025.10.1-trixie .
# Alpine
Get-Content Dockerfile.alpine | docker run --rm --interactive hadolint/hadolint:v2.13.1-beta4-debian
docker build --tag juergenzimmermann/buch:2025.10.1-alpine --file Dockerfile.alpine .Mit Docker Bake:
# Debian als default
docker buildx bake
docker buildx bake alpineMit dem Unterkommando history kann man ein Docker-Image und die einzelnen Layer
inspizieren:
docker history juergenzimmermann/buch:2025.10.1-trixie
docker history juergenzimmermann/buch:2025.10.1-alpineMit dem Unterkommando inspect kann man die Metadaten, z.B. Labels, zu einem
Image inspizieren:
docker inspect juergenzimmermann/buch:2025.10.1-trixie
docker inspect juergenzimmermann/buch:2025.10.1-alpineMit dem Unterkommando sbom (Software Bill of Materials) von docker kann man
inspizieren, welche Bestandteilen in einem Docker-Images enthalten sind, z.B.
npm-Packages oder Debian-Packages.
docker sbom juergenzimmermann/buch:2025.10.1-trixie
docker sbom juergenzimmermann/buch:2025.10.1-alpineMit Docker Compose und der Konfigurationsdatei compose.yml im Verzeichnis
.extras\compose lässt sich der Container mit dem Basis-Image mit Debian
Trixie (13) Slim folgendermaßen starten und später in einer weiteren
PowerShell herunterfahren.
cd .extras\compose\buch
# PowerShell fuer buch-Server mit Trixie-Image zzgl. DB-Server und Mailserver
docker compose up
# Nur zur Fehlersuche: weitere PowerShell für bash
cd .extras\compose\buch
docker compose exec buch bash
id
env
exit
# Fehlersuche im Netzwerk:
docker compose -f compose.busybox.yml up
docker compose exec busybox sh
nslookup postgres
exit
# 2. Powershell: buch-Server einschl. DB-Server und Mailserver herunterfahren
cd .extras\compose\buch
docker compose downESLint wird durch eslint.config.mts (rc = run command) konfiguriert und durch
folgendes pnpm-Skript ausgeführt:
pnpm run eslintMit dem ESLint Config Inspector kann man inspizieren, welche
- Plugins genutzt werden,
- Regeln aktiviert sind,
- aktivierten Regeln deprecated sind
npx @eslint/config-inspectorPrettier ist ein Formatierer, der durch prettier.config.mts (rc = run command)
konfiguriert und durch folgendes pnpm-Skript ausgeführt wird:
pnpm run prettierSiehe .extras\compose\sonarqube\ReadMe.md.
Mit Madge kann man zyklische Abhängigkeiten auflisten lassen: pnpm run madge.
Mit pnpm run madge:dep kann man sämtliche Abhängigkeiten in einer SVG-Datei
dependencies.svg visualisieren.
Mit dem Unterkommando audit von pnpm kann man npm_modules auf Sicherheitslücken
analysieren. Wenn man - sinnvollerweise - nur die dependencies aus package.json
berücksichtigen möchte, ergänzt man die Option -P ("Production"):
pnpm audit -PMit OWASP Dependency Check werden alle in node_modules installierten
Packages mit den CVE-Nummern der NIST-Datenbank abgeglichen.
Von https://nvd.nist.gov/developers/request-an-api-key fordert man einen "API Key"
an, um im Laufe des Semesters mit OWASP Dependency Check die benutzte Software
("3rd Party Libraries") auf Sicherheitslücken zu prüfen. Diesen API Key trägt
man im Skript scripts\dependency-check.mts als Wert der Variablen nvdApiKey ein.
cd scripts
node dependency-check.mtsMit dem Unterkommando quickview von Scout kann man sich zunächst einen
groben Überblick verschaffen, wieviele Sicherheitslücken in den Bibliotheken im
Image enthalten sind:
docker scout quickview juergenzimmermann/buch:2025.10.1-trixie
docker scout quickview juergenzimmermann/buch:2025.10.1-alpineDabei bedeutet:
- C ritical
- H igh
- M edium
- L ow
Sicherheitslücken sind als CVE-Records (CVE = Common Vulnerabilities and Exposures)
katalogisiert: https://www.cve.org (ursprünglich: https://cve.mitre.org/cve).
Übrigens bedeutet CPE in diesem Zusammenhang Common Platform Enumeration.
Die Details zu den CVE-Records im Image kann man durch das Unterkommando cves
von Scout auflisten:
docker scout cves juergenzimmermann/buch:2025.10.1-trixie
docker scout cves --format only-packages juergenzimmermann/buch:2025.10.1-trixieStatt der Kommandozeile kann man auch den Menüpunkt "Docker Scout" im Docker Dashboard verwenden.
Durch die Decorators @Api...() kann man OpenAPI bzw. Swagger in den
Controller-Klassen und -Methoden konfigurieren und dann in einem Webbrowser mit
https://localhost:3000/swagger aufrufen. Die Swagger JSON Datei kann man mit
https://localhost:3000/swagger-json abrufen.
Siehe .extras\doc\projekthandbuch\ReadMe.md.
Um die API-Dokumentation mit TypeDoc zu erstellen, ruft man in einer Powershell folgendes Kommando auf:
pnpm typedocSiehe .extras\compose\jenkins\ReadMe.md.
Visual Studio Code kann man kostenfrei herunterladen.
Tipps:
<Strg>#: Kommentare setzen und entfernen<F1>: Die Kommandopalette erscheint<Strg><Shift>v: Vorschau für MarkDown und AsciiDoctor<Alt>d: Vorschau für PlantUml- https://vscodecandothat.com: Kurze Videos zu VS Code
- https://www.youtube.com/watch?v=beNIDKgdzwQ: Video für Debugging
In Anlehnung an die Guidelines von TypeScript
- Klassennamen mit PascalCase
- Union-Types (mit Strings) statt Enums
- Attribute und Funktionen mit camelCase
#für private Properties- private Properties nicht mit vorangestelltem _
- Interfaces nicht mit vorangestelltem I
- Higher-Order Functions: [...].
forEach(), [...].filter() und [...].map() - Arrow-Functions statt function()
undefinedverwenden und nichtnull- Geschweifte Klammern bei if-Anweisungen
- Maximale Dateigröße: 400 Zeilen
- Maximale Funktionslänge: 75 Zeilen