Fortbildung

REST APIs

HTTP Grundlagen & Datenformate

Was ist HTTP?

HTTP = Hypertext Transfer Protocol

  • Transportprotokoll
  • Request-Response-Modell: Client fragt, Server antwortet
  • Zustandslos: Jede Anfrage steht für sich allein
  • Textbasiert und menschenlesbar
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server: ECAcc (nyd/D10E)
Content-Length: 1256

<!doctype html>
<!-- HTML content follows here -->

URL (Uniform Resource Locator)

https://api.example.com:443/users/123?sort=name&limit=10

Bestandteil Beispiel Beschreibung
Schema https:// Protokoll (http, https, ftp, …)
Host api.example.com Domain oder IP-Adresse
Port :443 Optional (http = 80, https = 443)
Pfad /users/123 Ressourcenpfad
Query ?sort=name&limit=8 Parameter

HTTP-Methoden

Methode Aktion Idempotent
GET Abrufen
POST Erstellen
PUT Ersetzen
PATCH Ändern ✗/✓
DELETE Löschen

Idempotenz

Mehrfaches Ausführen führt zum selben Ergebnis wie einmaliges Ausführen.

HTTP Statuscodes 1/2

2xx Erfolg

Code Bedeutung
200 OK – Anfrage erfolgreich
201 Created – Ressource erstellt
204 No Content – Erfolgreich, keine Daten

3xx Umleitung

Code Bedeutung
301 Moved Permanently – Dauerhaft verschoben
302 Found – Temporär umgeleitet
304 Not Modified – Cache nutzen

HTTP Statuscodes 2/2

4xx Client-Fehler

Code Bedeutung
400 Bad Request – Fehlerhafte Anfrage
401 Unauthorized – Nicht authentifiziert
403 Forbidden – Keine Berechtigung
404 Not Found – Ressource existiert nicht

5xx Server-Fehler

Code Bedeutung
500 Internal Error – Serverfehler
502 Bad Gateway – Upstream-Problem
503 Unavailable – Überlastet/Wartung

Request-Aufbau

Struktur

  1. Startzeile: Methode, Pfad, HTTP-Version

  2. Header: Metadaten

  3. Leerzeile: Trennt Header vom Body

  4. Body (optional): Nutzdaten

Beispiel: Update Nutzername

POST /api/v1/users/42 HTTP/1.1
Host: example.com
Accept: application/json
Authorization: Bearer xyz123

{ "name": "Max Mustermann" }

Beispiel: Hauptstadt von Deutschland anfragen

GET /v3.1/name/germany?fields=capital HTTP/1.1
Host: restcountries.com
Accept: application/json

Response-Aufbau

Struktur

  1. Statuszeile: HTTP-Version, Statuscode

  2. Header: Metadaten

  3. Leerzeile: Trennt Header vom Body

  4. Body: Daten

Beispiel: Update Nutzername

HTTP/1.1 200 OK

Beispiel: Hauptstadt von Deutschland anfragen

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=3600

[
  {
    "capital": [
      "Berlin"
    ]
  }
]

Header (Request)

Header Funktion Beispiel
Content-Type Was schicke ich? application/json
Accept Was möchte ich zurück? application/json, text/html
Authorization Authentifizierung Bearer eyJhbG...
User-Agent Wer fragt an? Mozilla/5.0...
Host Welcher Server? api.example.com

Header (Response)

Header Funktion Beispiel
Content-Type Format der Antwort application/json
Content-Length Größe in Bytes 1234
Cache-Control Caching-Regeln max-age=3600, public
ETag Versions-Fingerabdruck "33a64df5"
Location Weiterleitung bei 3xx / Neue Ressource bei 201 http://example.com/users/42

JSON

JavaScript Object Notation

  • Schlüssel-Wert-Paare in geschweiften Klammern { }
  • Arrays in eckigen Klammern [ ]
  • Datentypen: String, Number, Boolean, null, Object, Array
{
  "name": "Max Mustermann",
  "alter": 28,
  "aktiv": true,
  "adresse": {
    "stadt": "Berlin",
    "plz": "10115"
  },
  "hobbies": ["Lesen", "Wandern", "Kochen"]
}

curl (Client and URL)

  • Kommandozeilentool für HTTP-Anfragen
  • Auf den meisten Systemen verfügbar
  • Gut für Automatisierung und Debugging
$ curl https://restcountries.com/v3.1/name/germany?fields=capital
[{"capital":["Berlin"]}]
Flag Wirkung
-i Zeigt Response-Header
-v Zeigt kompletten Request/Response (verbose)
-X POST Setzt HTTP-Methode explizit

Übung 1 – GET-Requests

Aufgaben:

  1. Öffentliche API aufrufen: curl https://restcountries.com/v3.1/name/germany?fields=capital

  2. Response-Header anschauen: curl -i https://restcountries.com/v3.1/name/germany?fields=capital

  3. Verbose-Modus ausprobieren: curl -v https://restcountries.com/v3.1/name/germany?fields=capital

curl – Header und Body

Flag Wirkung
-H "Header: Wert" Setzt einen Header, mehrfach möglich
-d '...' Setzt den Request-Body
--json '...' Kurzform für -H "Content-Type: application/json" -d '{...}'
curl \
  https://rest.acosci.de/api/v1/public/messages \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"author": "Max", "title": "foobar", "content": "Hello World!"}'
curl \
  https://rest.acosci.de/api/v1/public/messages \
  -X POST \
  --json '{"author": "Max", "title": "foobar",  "content": "Hello World!"}'

Übung 2 – POST-Requests

Basis-URL: https://rest.acosci.de/api/v1/public/messages Message Board ansehen: https://rest.acosci.de/board/public Aufgaben:

  1. Ruft alle Nachrichten ab (GET) – was fällt am Response auf?
  2. Schickt eine Nachricht ans Board (POST mit –json) curl https://rest.acosci.de/api/v1/public/messages -X POST --json '{"author": "NAME", "title": "TITEL", "content": "NACHRICHT"}'
  3. Versucht, Fehler zu provozieren:
  • Was passiert ohne Body?
  • Was passiert mit kaputtem JSON?
  • Was passiert, wenn ihr die falsche Methode nutzt?
  1. Schaut euch die Response-Header an (-i) – welche Statuscodes bekommt ihr?

Bonus: Was könnte man mit den Nachrichten noch alles machen? Welche HTTP-Methoden habt ihr noch nicht benutzt?

REST Prinzipien

Was ist REST?

REST = REpresentational State Transfer

  • Architekturstil für verteilte Systeme
  • Zustandslos (stateless)

Wichtig: REST ≠ HTTP

  • HTTP = Protokoll (wie wird kommuniziert)
  • REST = Architekturstil (wie wird die API strukturiert)

REST nutzt HTTP, ist aber nicht darauf beschränkt.

Warnung

Viele APIs nennen sich “RESTful”, befolgen aber nicht alle REST-Prinzipien. Das ist OK!

REST-Prinzipien: Überblick

  1. Client-Server-Architektur
  2. Statelessness (Zustandslosigkeit)
  3. Cacheability (Cachebarkeit)
  4. Uniform Interface (Einheitliche Schnittstelle)
  5. Layered System (Schichtenarchitektur)
  6. Code on Demand (optional; Server kann ausführbaren Code an den Client schicken)

1. Client-Server-Architektur

Trennung von Client und Server

  • Client kennt nur die Schnittstelle (API)
  • Server verwaltet Daten und Geschäftslogik

Vorteile:

  • Unabhängige Entwicklung
  • Skalierbarkeit
  • Verschiedene Clients (Web, Mobile, Desktop)

2. Statelessness

Zustandslos: Jeder Request enthält alle notwendigen Informationen.

# ❌ Stateful (Session auf Server)
GET /messages/next HTTP/1.1
Cookie: session=abc123

# ✅ Stateless (alles im Request)
GET /messages?offset=10&limit=5 HTTP/1.1
Authorization: Bearer eyJhbGc...

Vorteile:

  • Skalierbarkeit (Load Balancing)
  • Einfacheres Debugging
  • Cache-freundlich

3. Uniform Interface: Prinzipien

  1. Identification of Resources Jede Ressource hat eine eindeutige ID (URL)
  2. Manipulation through Representations Man arbeitet nicht direkt mit der Ressource, sondern mit einer Repräsentation (JSON, XML, HTML)
  3. Self-descriptive Messages Jede Nachricht enthält genug Informationen, um verstanden zu werden (Header, Status Codes, Content-Type)

3. Identification of Resources

Ressource = Jedes “Ding” mit einer eindeutigen ID

Beispiele: - Alle Nachrichten: /messages - Nachricht mit ID 1: /messages/1 - Benutzer alice: /users/alice

Ressourcen sind Nomen (Dinge), keine Verben (Aktionen)!

3. Identification of Resources

Best Practices:

  1. Nomen verwenden, keine Verben
  2. Plural für Sammlungen: /messages, nicht /message
  3. Konsistente Benennung: snake_case oder camelCase
  4. Versionierung: /v1/messages, /v2/messages
  5. Filter als Query-Parameter: ?status=active
  6. Dokumentation: OpenAPI, Swagger (später)

3. Identification of Resources

❌ Schlecht ✅ Gut
GET /getMessages GET /messages
GET /getMessage?id=1 GET /messages/1
POST /createMessage POST /messages
POST /updateMessage?id=1 PUT /messages/1
POST /deleteMessage?id=1 DELETE /messages/1

3. Identification of Resources

Hierarchien:

GET /users/alice/messages       # Nachrichten von alice
GET /users/alice/messages/1     # Nachricht 1 von alice

Filter & Pagination:

GET /messages?author=alice&limit=10&offset=0
GET /messages?created_after=2025-01-01

3. Manipulation through Representations

Der Client arbeitet nie direkt mit den Daten — nur mit einer Repräsentation (z.B. JSON). Client ←→ JSON-Repräsentation ←→ Server ←→ Datenbank. Intern könnte der Server die Daten speichern wie er will: PostgreSQL, MongoDB, eine Textdatei — der Client merkt keinen Unterschied.

# Beispiel: Eine Nachricht im MessageBoard
{
  "id": 1,
  "author": "Alice",
  "message": "Hallo Welt",
  "created_at": "2025-06-01T10:00:00Z"
}

Vorteile:

  • Backend kann Datenbank wechseln, ohne dass Clients angepasst werden müssen
  • Dieselbe Ressource kann unterschiedlich dargestellt werden (JSON, XML, HTML) — je nach Accept-Header
  • Interne Felder (z.B. password_hash) bleiben verborgen

3. Uniform Interface: Self-descriptive Messages

  • Pfad (URL): Welche Ressource?
  • HTTP-Methode: Was wird mit der Ressource gemacht?
  • Header: z.B. Content-Type: Wie sehen die Daten aus?
  • Status-Codes: Was ist passiert? 4XX/5XX -> Fehler 2XX -> Erfolg

3. Self-descriptive Messages

CRUD → HTTP-Methoden

CRUD HTTP-Methode Beispiel
Create POST POST /messages
Read GET GET /messages/1
Update PUT / PATCH PUT /messages/1
Delete DELETE DELETE /messages/1

3. Self-descriptive Messages

PUT vs. PATCH

PUT PATCH
Operation Komplette Ersetzung Teilweise Änderung
Idempotent ✅ Ja ✅ Ja (meist)
Body Komplettes Objekt Nur geänderte Felder

Beispiel PUT:

PUT /messages/1
{"title": "Neu", "content": "Neuer Inhalt"}

Beispiel PATCH:

PATCH /messages/1
{"title": "Neu"}  // content bleibt unverändert

3. Self-descriptive Messages

Fehlerbehandlung

Gute Fehlerantworten:

{
  "error": "validation_failed",
  "message": "Titel ist zu lang",
  "details": {
    "field": "title",
    "max_length": 200,
    "actual_length": 250
  }
}

Konsistente Struktur über alle Endpunkte hinweg!

Beispiel: MessageBoard-API

# Ressourcen
GET    /api/v1/messages          # Liste aller Nachrichten
GET    /api/v1/messages/1        # Eine Nachricht
POST   /api/v1/messages          # Neue Nachricht
PUT    /api/v1/messages/1        # Nachricht ändern
DELETE /api/v1/messages/1        # Nachricht löschen

# Authentifizierung
POST   /api/v1/auth/login        # Login
POST   /api/v1/auth/refresh      # Token erneuern

# Admin
POST   /api/v1/admin/reset       # DB zurücksetzen

4. Cachability

Eigener Block später: Caching

5. Layered System

Zwischen Client und Server können transparente Zwischenschichten liegen. Ein Client weiß nicht, ob er mit dem Server, einem Proxy oder einem Load Balancer spricht.

graph LR
    subgraph " "
        direction LR
        C1[Client] --> S1[Server]
    end

    subgraph " "
        direction LR
        C2[Client] --> LB[Load Balancer] --> Cache --> S2[Server]
    end

    style LB stroke-dasharray: 5 5
    style Cache stroke-dasharray: 5 5

Zusammenfassung

  • REST = Architekturstil für APIs
  • Ressourcen = Nomen mit eindeutigen URIs
  • HTTP-Methoden = Operationen auf Ressourcen
  • Stateless = Jeder Request ist unabhängig
  • Uniform Interface = Konsistente API-Struktur

Übung 3

Basis-URL: https://rest.acosci.de/api/v1/public/messages

Message Board ansehen: https://rest.acosci.de/board/public

Aufgaben:

  1. Ruft alle Nachrichten ab (vgl. Übung 1)
  2. Ruft eine einzelne Nachricht ab
  3. Löscht eine Nachricht
  4. Versucht, eine Nachricht zu ändern (PUT oder PATCH) — was passiert?

Diskussion: Jeder kann fremde Nachrichten löschen und ändern. Wie könnte man das verhindern?

Authentifizierung

Authentifizierung vs. Autorisierung

Authentifizierung “Wer bist du?”

  • Identität bestätigen
  • Login: Benutzername + Passwort
  • Ergebnis: Token / Session
  • HTTP: 401 Unauthorized

Autorisierung “Was darfst du?”

  • Berechtigungen prüfen
  • Darf dieser Nutzer das?
  • Ergebnis: Zugriff erlaubt / verweigert
  • HTTP: 403 Forbidden

Analogie

Authentifizierung = Ausweis zeigen am Eingang.

Autorisierung = Zutritt zum Serverraum nur für Admins.

Einschub: Base64-Kodierung

  • Übersetzt beliebige Binärdaten in Text
  • 64 Zeichen: A–Z, a–z, 0–9, +, /
  • = als Padding
  • Pro Zeichen werden 6 Bit kodiert
  • Keine Verschlüsselung, nur Kodierung!

Anwendungsfälle:

  • Basic Authentication
  • Eingebettete Bilder in HTML/CSS
  • Dateianhänge in E-Mails

Beispiel:

Hello              →  SGFsbG8=
REST               →  UkVTVA==
username:password  →  dXNlcm5hbWU6cGFzc3dvcmQ=

JWT — JSON Web Token

  • Offener Standard (RFC 7519)
  • Kompaktes, selbständig verifizierbares Token
  • Besteht aus drei Teilen, getrennt durch .
  • Jeder Teil ist Base64url-kodiert
  • Kein zentraler Server zur Verifikation nötig

Header.Payload.Signature

Warnung

Base64 ist keine Verschlüsselung — der Inhalt ist lesbar!

JWT — Aufbau

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30

Header — Algorithmus & Typ

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload — Claims (Nutzdaten)

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}

Signatur — Integritätsschutz

HMACSHA256(
  base64url(header) + "." +
  base64url(payload),
  secret
)

→ Prüft, ob das Token unverändert ist

JWT — Claims

Standardisierte Claims (registered):

Feld Bedeutung Beispiel
iss Aussteller (issuer) example.com
sub Nutzer-ID (subject) user_42
aud Zielgruppe (audience) api.example.com
exp Ablaufzeit (expiration) 1516239022
nbf Gültig ab (not before) 1516236022
iat Ausstelldatum (issued at) 1516236022
jti Eindeutige Token-ID (JWT ID) abc123

Eigene Claims können frei hinzugefügt werden ("admin": true, "role": "teacher").

Hinweis

exp, nbf und iat sind Unix-Timestamps (Sekunden seit 01.01.1970).

JWT — Verifikation & Grenzen

Vorteil: Dezentrale Verifikation

  • Reduziert Zugriffe auf Datenbanken
  • Entlastet Authentifizierungsserver
Server empfängt Token
→ Signatur prüfen
→ exp / nbf prüfen
→ Kein Datenbankaufruf nötig

JWT — Verifikation & Grenzen

Symmetrisch (HMAC)

alg: HS256

  • Ein gemeinsames Secret
  • Wer verifizieren kann, kann auch ausstellen
  • Nur für interne Dienste geeignet
Auth-Server ←→ secret ←→ API-Server

Asymmetrisch (RSA / ECDSA)

alg: RS256 / ES256

  • Auth-Server besitzt Private Key (signiert)
  • API-Server kennt nur Public Key (verifiziert)
  • API-Server kann keine Tokens fälschen
Auth-Server → private key → Token
API-Server  → public key  → Verifikation

Nachteil: Tokens können (in der Regel) nicht zurückgezogen werden

Warnung

Ein gültiges Token gibt Zugriff auf alle Ressourcen, für die es ausgestellt wurde. Deshalb werden bei kritischen Aktionen (Passwort ändern, Zahlung) oft nochmal Credentials abgefragt.

Hinweis

Ausnahme: Mit jti (JWT ID) kann ein Server eine Blacklist führen — dann ist Widerruf möglich, erfordert aber wieder einen zentralen Lookup.

Bekannte Konsequenz: > “Alle Geräte abmelden — dies kann bis zu 30 Minuten dauern.”

Access Token & Refresh Token

Das Problem: Kurzlebige Tokens sind sicher, aber lästig. Langlebige Tokens sind bequem, aber riskant.

Lösung: Zwei Tokens

Access Token Refresh Token
Lebenszeit Kurz (~5–30 min) Lang (~7–90 Tage)
Verwendung Jede API-Anfrage Nur für neuen Access Token
Widerrufbar Nein Ja (zentral gespeichert)
Risiko bei Diebstahl Gering (läuft bald ab) Hoch

Ablauf:

Login → Access Token + Refresh Token
API-Anfrage → Access Token im Header
Access Token abgelaufen → Refresh Token → neuer Access Token
Refresh Token abgelaufen → erneuter Login

JWT mit REST verwenden

Standard: Authorization Header

GET /api/v1/messages HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Alternative: Cookie (HttpOnly, Secure)

Cookie: access_token=eyJhbGc...
  • Browser setzt ihn automatisch
  • JS-Code kann nicht darauf zugreifen (XSS-Schutz)
  • Anfällig für CSRF (braucht Gegenmassnahmen)

Nicht empfohlen: Query-Parameter

GET /api/v1/messages?token=eyJhbGc...
  • Token landet in Server-Logs und Browser-Historie
  • Nur für Sonderfälle (z.B. einmalige Download-Links)

Fehlerszenarien

Szenario Statuscode Beispiel-Response
Kein Token mitgeschickt 401 "detail": "Not authenticated"
Token abgelaufen 401 "detail": "Token expired"
Token manipuliert 401 "detail": "Invalid token"
Token gültig, aber keine Berechtigung 403 "detail": "Not enough permissions"

Hinweis

401 → Problem mit dem Token selbst (fehlt, abgelaufen, ungültig) 403 → Token ist gültig, aber der Nutzer darf das nicht

Zusammenfassung

  • Authentifizierung (401) vs. Autorisierung (403)
  • JWT = selbständig verifizierbares Token aus Header, Payload, Signatur
  • Base64 ≠ Verschlüsselung — Payload ist lesbar
  • Access Token (kurzlebig) + Refresh Token (langlebig, widerrufbar)
  • Bearer Header ist der Standard für API-Anfragen

Übung 4

Basis-URL: https://rest.acosci.de/api/v1/messages (Ohne public/)

Message Board ansehen: https://rest.acosci.de/board

Aufgaben:

  1. Versucht Nachricht 1 (von alice) zu löschen, was passiert?
  2. Registriert euch:
curl https://rest.acosci.de/api/v1/auth/register \
  -X POST \
  --json '{"username": "EUER_NAME", "password": "abc123"}'
  1. Loggt euch ein — was bekommt ihr zurück?
curl https://rest.acosci.de/api/v1/auth/login \
  -X POST \
  --json '{"username": "EUER_NAME", "password": "abc123"}'
  1. Kopiert euren Access Token und schreibt eine Nachricht:
curl https://rest.acosci.de/api/v1/messages \
  -X POST \
  -H "Authorization: Bearer EUER_TOKEN" \
  --json '{"title": "TITEL", "content": "NACHRICHT"}'
  1. Versucht, eure Nachricht ohne Token zu löschen — was passiert?
  2. Versucht, die Nachricht von jemand anderen zu löschen — was passiert?

Diskussion: Schaut euch euren Token auf https://jwt.io an — was steht drin? Welche Claims erkennt ihr wieder?

Dokumentation (OpenAPI)

Was ist OpenAPI?

  • Früher bekannt als Swagger, seit 2016 OpenAPI Specification
  • Maschinenlesbare Beschreibung einer REST-API
  • Format: JSON oder YAML
  • Standard der OpenAPI Initiative (Linux Foundation)

Hinweis

Eine OpenAPI-Datei ist ein Vertrag zwischen API-Anbieter und Nutzer – beide Seiten wissen genau, was erwartet wird.

Wozu nützt OpenAPI?

Dokumentation

Aus der Spec wird automatisch eine interaktive Doku generiert: Swagger UI, Redoc, …

Code-Generierung

Client-Bibliotheken, Server-Stubs und Typen können direkt aus der Spec erzeugt werden.

Teamarbeit

Frontend und Backend können parallel entwickeln, sobald der Vertrag (die Spec) feststeht.

Aufbau — Überblick

{
  "openapi": "3.1.0",
  "info": {
    "title": "MessageBoard API",
    "version": "0.1.0"
  },
  "paths": {
    "/api/v1/messages": { ... },
    "/api/v1/auth/login": { ... }
  },
  "components": {
    "schemas": { ... },
    "securitySchemes": { ... }
  }
}
Bereich Inhalt
info Titel, Version, Beschreibung
paths Alle Endpunkte mit Methoden, Parametern, Responses
components Wiederverwendbare Schemas und Security-Definitionen

paths — JSON vs. Swagger UI

In der Spec (openapi.json), gekürzt

"/api/v1/auth/login": {
  "post": {
    "summary": "Einloggen und Token erhalten",
    "requestBody": {
      "required": true,
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/LoginRequest"
          }
        }
      }
    },
    "responses": {
      "200": { "description": "Login erfolgreich" },
      "401": { "description": "Ungültige Anmeldedaten" },
      "403": {"description": "Konto deaktiviert"}
    }
  }
}

In Swagger UI: → https://rest.acosci.de/openapi/

Tipp

Das Schloss-Symbol zeigt: dieser Endpunkt braucht Authentifizierung.

Endpunkte ohne Schloss sind öffentlich.

components/schemas — Das Message-Objekt

"Message": {
  "type": "object",
  "required": ["id", "title", "content", "author", "created_at"],
  "properties": {
    "id":         { "type": "integer", "example": 1 },
    "title":      { "type": "string", "maxLength": 200 },
    "content":    { "type": "string", "description": "Inhalt der Nachricht" },
    "author":     { "type": "string" },
    "created_at": { "type": "string", "format": "date-time" },
    "updated_at": { "type": "string", "format": "date-time", "nullable": true }
  }
}
  • required → diese Felder sind immer vorhanden
  • nullable: true → Feld kann null sein (z. B. title ist optional)
  • $ref → Verweis auf ein anderes Schema (Wiederverwendung)

Hinweis

Das ist exakt das JSON, das ihr bei GET /api/v1/messages zurückbekommt.

components/securitySchemes - Authentifizierung

Für JWT-Token im Header:

"securitySchemes": {
   "bearerAuth": {
      "type": "http",
      "scheme": "bearer",
      "bearerFormat": "JWT",
      "description": "JWT Bearer Token. Erhalten über `POST /api/v1/auth/login`."
   }
}

Hinweis

securitySchemes sind sehr spezifisch auf die verwendete Authentifizierung!

Swagger UI — Wie nutze ich es?

Schritt 1 — Endpunkt aufklappen Auf einen Endpunkt klicken → Methode, Parameter, Schemas werden angezeigt.

Schritt 2 — Authentifizieren Oben rechts: Authorize → Bearer Token eingeben (aus Block 3 bekannt).

Schritt 3 — Try it out Button „Try it out” → Parameter ausfüllen → Execute

Schritt 4 — Response lesen Statuscode, Response-Header und Body werden direkt angezeigt.

Tipp

Swagger UI führt denselben HTTP-Request aus wie curl – nur mit einer grafischen Oberfläche.

Übung 5 - OpenAPI

SwaggerUI: https://rest.acosci.de/openapi/

OpenAPI JSON: https://rest.acosci.de/openapi/openapi.json

Aufgabe: Nur mit der API-Dokumentation (kein Spickzettel!):

  1. Listet alle Endpunkte der MessageBoard-API auf. Welche brauchen Authentifizierung?
  2. Erstellt eine eigene Nachricht — diesmal direkt über Swagger UI.
  3. Wie verändert man eine Nachricht? Welche Parameter werden benötigt?

Bonus: Erinnert euch an Übung 3, Aufgabe 4 — ihr konntet eine Nachricht nicht ändern, weil euch die Felder fehlten. Holt das jetzt nach: Ändert eine Nachricht per cURL, mit der Dokumentation als Hilfe.

Diskussion: Ihr habt das MessageBoard jetzt auf drei Arten bedient: cURL blind, Swagger UI und cURL mit Doku. Was war am einfachsten? Wo seht ihr Vor- / Nachteile?

Was ist Hoppscotch?

  • Open-Source GUI-Tool
  • Läuft im Browser — keine Installation nötig
  • Kein Account erforderlich
  • Alle Daten bleiben lokal (DSGVO-freundlich)

Tipp

Ideal für den Unterricht: kostenlos, sofort einsatzbereit, funktioniert auf jedem Gerät mit Browser.

OpenAPI-Import

Statt Endpunkte manuell einzutippen: Spec einmal importieren — alle Endpunkte mit Parametern, Schemas und Beschreibungen sind sofort verfügbar.

So geht’s:

  1. Hoppscotch öffnen: https://hoppscotch.io
  2. SammlungenImportierenOpenAPI
  3. URL einfügen: https://rest.acosci.de/openapi/openapi.json

Hinweis

Hoppscotch liest dieselbe openapi.json, die wir gerade analysiert haben.

Übung 6 — MessageBoard mit Hoppscotch

Hoppscotch: https://hoppscotch.io

OpenAPI-Spec: https://rest.acosci.de/openapi/openapi.json

Aufgaben:

  1. Importiert die OpenAPI-Spec als Collection.
  2. Führt dieselben Operationen wie mit cURL / Swagger UI durch:
    • Einloggen (oder Token wiederverwenden)
    • Eigene Nachricht erstellen
    • Eigene Nachricht bearbeiten oder löschen
  3. Erstellt eine Nachricht — vergleicht: Wie viel musstet ihr selbst wissen vs. wie viel hat Hoppscotch euch vorgegeben?

Diskussion: Ihr habt jetzt cURL, Swagger UI und Hoppscotch benutzt. Wenn ihr euren Azubis nur ein Tool beibringen dürftet — welches wäre es und warum?

Caching

Caching

Problem: Client fragt immer wieder dieselben Daten ab - unnötige Last und Latenz. Lösung: Server signalisiert, ob und wie lange eine Antwort gecacht werden darf.

Vorteile:

  • Weniger Netzwerk-Traffic
  • Schnellere Antworten
  • Geringere Server-Last

Hinweis

Caching ist eines der sechs REST-Prinzipien — der Server muss kennzeichnen, ob eine Antwort cachebar ist.

Cache-Control

Der Server steuert das Caching über den Cache-Control-Header:

HTTP/1.1 200 OK
Cache-Control: max-age=3600, public
Optionen Bedeutung
max-age=3600 3600 Sekunden (1h) gültig
public Jeder darf cachen (auch Proxies)
private Nur der Client darf cachen
no-store Nie cachen (z.B. sensible Daten)
no-cache Cachen erlaubt, aber vor Nutzung validieren

Warnung

no-cache ≠ “nicht cachen”! Es bedeutet: immer erst beim Server nachfragen, ob sich etwas geändert hat.

ETag & Bedingte Requests (no-cache)

Problem: max-age abgelaufen — hat sich die Ressource wirklich geändert?

Lösung: Server vergibt einen Fingerabdruck (ETag). Client fragt: “Hat sich etwas geändert?”

  1. Erster Request:
GET /api/v1/messages/1 →  200 OK
                          ETag: "a1b2c3"
  1. Späterer Request:
   GET /api/v1/messages/1
   If-None-Match: "a1b2c3"  →  304 Not Modified
                                (kein Body, Cache nutzen)
  1. Nach Änderung:
   GET /api/v1/messages/1
   If-None-Match: "a1b2c3"  →  200 OK
                                ETag: "d4e5f6"
                                (neuer Body, Cache aktualisieren)

Demo - Caching am MessageBoard

  1. Request mit verbose — ETag im Response suchen
curl -v https://rest.acosci.de/api/v1/public/messages/1
  1. Bedingter Request mit If-None-Match
curl -v -H "If-None-Match: \"EUER_ETAG\"" \
 https://rest.acosci.de/api/v1/public/messages/1

Tipp

Im Browser passiert das automatisch — bei jedem Seitenaufruf prüft der Browser ETags und spart so Bandbreite.

Zusammenfassung Caching

  • Cache-Control bestimmt ob und wie lange gecacht wird
  • ETag + If-None-Match ermöglichen Validierung ohne erneuten Download
  • 304 Not Modified = “Deine Version ist noch aktuell”
  • Spart Bandbreite, reduziert Last, verbessert Performance

Ausblick

Passwörter im Backend

Nie Klartext speichern

Passwort: "abc123"
      ↓ + Salt (zufälliger Wert)
      ↓ + Hash-Funktion (bcrypt, argon2)
Gespeichert: "$2b$12$LJ3m4ys..."
Konzept Zweck
Hash Einweg-Funktion — vom Hash kann man nicht auf das Passwort zurückrechnen
Salt Zufälliger Zusatz pro Nutzer — verhindert, dass gleiche Passwörter gleiche Hashes ergeben

In der Datenbank wird das Passwort-Hash und der Salt gespeichert.

GraphQL

Problem: REST liefert feste Datenstrukturen — oft zu viel oder zu wenig.

REST:    GET /users/1          → ganzes User-Objekt (Over-fetching)
         GET /users/1/messages → zweiter Request nötig (Under-fetching)
query {
  user(id: 1) {
    name
    messages {
      title
      created_at
    }
  }
}
REST GraphQL
Endpunkte Viele (/users, /messages, …) Einer (/graphql)
Datenmenge Server bestimmt Client bestimmt
Caching Einfach (HTTP-Caching) Komplex (eigene Lösungen)
Einsatz Standard für öffentliche APIs Flexible Frontends, Mobile Apps

gRPC

REST gRPC
Format JSON (Text) Protocol Buffers (Binär)
Protokoll HTTP/1.1 oder 2 HTTP/2
Kontrakt OpenAPI (optional) .proto-Datei (verpflichtend)
Streaming Nein (Workarounds) Bidirektional eingebaut
Einsatz Öffentliche APIs, Web Microservices, interne Kommunikation
// Beispiel: messages.proto
service MessageBoard {
  rpc GetMessage (MessageRequest) returns (Message);
}
message MessageRequest {
  int32 id = 1;
}

Vorteil: Schnell, typsicher, Code-Generierung.

Nachteil: Nicht menschenlesbar, Browser-Support eingeschränkt.

WebSockets

Problem: HTTP ist Request-Response — der Server kann nicht von sich aus senden.

Lösung: WebSocket öffnet eine dauerhafte, bidirektionale Verbindung.

HTTP:        Client → Request → Server → Response → Ende
WebSocket:   Client ↔ Server (dauerhaft offen, beide senden jederzeit)
REST WebSocket
Verbindung Pro Request neu Dauerhaft offen
Richtung Client → Server Bidirektional
Einsatz CRUD, Abfragen Chat, Live-Daten, Gaming
Overhead Header bei jedem Request Einmal Handshake, dann minimal

Hinweis

Ein Chat wäre eine klassische WebSocket-Anwendung — neue Nachrichten könnten live erscheinen, ohne die Seite neu zu laden.