Skip to content

MatthiasStudies/modern-serverapplications-and-webapps-with-typescript

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hinweise zum Programmierbeispiel

Juergen Zimmermann

Diese Datei ist in Markdown geschrieben und kann mit <Strg><Shift>v in 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.

Inhalt


Vorbereitung von Prisma für Nest

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 emitDecoratorMetadata den Kommentar entfernen
    • die Option noEmit auskommentieren
    • die Option allowImportingTsExtensions auskommentieren
  • Der Prisma-Client muss deshalb auch neu generiert werden, d.h.
    • das Verzeichnis src\generated wird gelöscht und
    • pnpx prisma generate wird in der PowerShell aufgerufen.
  • Die bisherigen Beispieldateien beispiele.mts und beispiele-write.mts für den "alten" Prisma-Client können deshalb nicht mehr funktionieren, weshalb man sie am einfachsten aus dem Projekt löscht.

Download- und ggf. Upload Geschwindigkeit

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.


Vorbereitung der Installation

  • 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.


ES Modules (= ESM)

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:

Unterstützung für ESM ist notwendig in:

  • Node
  • TypeScript
  • ts-node
  • ts-jest: versteht noch nicht die Datei-Endung .mts und beim Import .mjs
  • VS Code
  • Node innerhalb von Jenkins

Node Best Practices

Sehr empfehlenswert ist https://github.com/goldbergyoni/nodebestpractices


Lokaler Appserver mit Nest und dem Watch-Modus

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.


Postman: Desktop-Anwendung und Extension für VS Code

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.

Registrieren und Installieren

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.

Workspace anlegen

Ü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 buch und im Eingabefeld Summary z.B. REST- und GraphQL-Requests für den Appserver.
  • Abschließend den Button Create anklicken.

Environments

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.

Collections und Folders

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.

Requests

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-Type und als zugehörigen Wert application/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.

Variable

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.

Tokens durch Pre-request Scripts und Authorization-Header

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.

Tests in Postman

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.

Erweiterung für VS Code

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.

Invoke-WebRequest in der PowerShell

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 -SkipCertificateCheck

Tests aufrufen

Folgende 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 t

Bei 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:47

Docker-Image und Docker Compose

Minimales Basis-Image

Fü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

Image erstellen

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 alpine

Image inspizieren

docker history

Mit 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-alpine

docker inspect

Mit 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-alpine

docker sbom

Mit 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-alpine

Docker Compose

Mit 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 down

Statische Codeanalyse und Formatierer

ESLint

ESLint wird durch eslint.config.mts (rc = run command) konfiguriert und durch folgendes pnpm-Skript ausgeführt:

    pnpm run eslint

Mit dem ESLint Config Inspector kann man inspizieren, welche

  • Plugins genutzt werden,
  • Regeln aktiviert sind,
  • aktivierten Regeln deprecated sind
    npx @eslint/config-inspector

Prettier

Prettier ist ein Formatierer, der durch prettier.config.mts (rc = run command) konfiguriert und durch folgendes pnpm-Skript ausgeführt wird:

    pnpm run prettier

SonarQube

Siehe .extras\compose\sonarqube\ReadMe.md.

Madge

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.


Sicherheitslücken

pnpm audit

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 -P

OWASP Dependency Check

Mit 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.mts

Docker Scout

Mit 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-alpine

Dabei 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-trixie

Statt der Kommandozeile kann man auch den Menüpunkt "Docker Scout" im Docker Dashboard verwenden.


OpenAPI

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.


AsciiDoctor und PlantUML

Siehe .extras\doc\projekthandbuch\ReadMe.md.


TypeDoc

Um die API-Dokumentation mit TypeDoc zu erstellen, ruft man in einer Powershell folgendes Kommando auf:

    pnpm typedoc

Continuous Integration mit Jenkins

Siehe .extras\compose\jenkins\ReadMe.md.


Visual Studio Code

Visual Studio Code kann man kostenfrei herunterladen.

Tipps:


Empfohlene Code-Konventionen

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()
  • undefined verwenden und nicht null
  • Geschweifte Klammern bei if-Anweisungen
  • Maximale Dateigröße: 400 Zeilen
  • Maximale Funktionslänge: 75 Zeilen

About

Code project for the modern serverapplications and webapps with typescript lecture WiSe 2025/2026 at the HKA

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors