====== LU17 – CRUD mit Express & MySQL ======
===== Learning Objectives =====
* Sie können eine **MySQL-Datenbank** aus Ihrem Express-Server heraus ansprechen.
* Sie können CRUD-Routen für ''posts'' so erweitern, dass sie mit einer **echten Tabelle ''post''** arbeiten.
* Sie setzen einfache **Validierung** ein (Pflichtfelder prüfen).
* Sie verwenden passende **HTTP-Statuscodes** (200, 201, 400, 404, 500).
* Sie testen alle Operationen mit **Postman**.
===== Ausgangslage =====
In LU16 haben Sie eine kleine API für Social-Media-Posts gebaut:
* In-Memory-Liste ''posts'' im Code,
* Routen wie:
- ''GET /posts''
- ''GET /posts/:id''
- ''POST /posts''
Jetzt machen wir einen wichtigen Schritt in Richtung „echte“ Anwendung:
* Die Daten kommen nicht mehr aus einer JS-Liste,
* sondern aus einer **MySQL-Tabelle ''post''**,
* Ihr Express-Server wird zur **Brücke** zwischen Client (Postman/Browser) und Datenbank.
===== Vorbereitung: MySQL-Tabelle ''post'' =====
Eine mögliche Tabellenstruktur (vereinfacht):
^ Spalte ^ Datentyp ^ Beschreibung ^
| ''post_id'' | INT, PK, AI | Primärschlüssel |
| ''user_id'' | INT | Referenz auf User (FK) |
| ''title'' | VARCHAR(255) | Titel des Posts |
| ''image_url'' | VARCHAR(512) | Bild-URL |
| ''description'' | TEXT | Beschreibungstext |
| ''likes'' | INT | Anzahl Likes |
Diese Tabelle können Sie wie gewohnt mit einem SQL-DDL-Skript anlegen.
(Entweder vorgegeben im Unterricht oder von Ihnen selbst erstellt.)
===== MySQL aus Node.js ansprechen =====
Wir verwenden das Paket **''mysql2''** für die Verbindung:
==== 1. Installation von mysql2 ====
Im Projektordner (Terminal in WebStorm):
npm install mysql2
Dadurch wird die Bibliothek in ''node_modules'' installiert und in ''package.json'' als Abhängigkeit eingetragen.
==== 2. Verbindung zur Datenbank herstellen ====
Wir erweitern unseren Server aus LU16 um eine Datenbankverbindung.
Alles bleibt weiterhin in einer Datei (z.B. ''index.js''), um es für das Modul einfach zu halten.
import express from 'express';
import mysql from 'mysql2';
const app = express();
const port = 3000;
app.use(express.json());
// Verbindung zur MySQL-Datenbank
const db = mysql.createConnection({
host: 'localhost',
database: 'social_media', // Ihre DB
user: 'restrictedUser', // AppUser, nicht root
password: 'SafePassword123'
});
db.connect((err) => {
if (err) {
console.error('DB-Verbindung fehlgeschlagen:', err);
return;
}
console.log('Mit MySQL verbunden');
});
// Test-Route
app.get('/', (req, res) => {
res.send('API mit Datenbank ist online');
});
app.listen(port, () => {
console.log(`API läuft auf http://localhost:${port}`);
});
Wenn Sie den Server starten (''npm run dev'') und im Terminal
**„Mit MySQL verbunden“** sehen, ist die Verbindung erfolgreich.
===== READ – Posts aus der Datenbank holen =====
Jetzt ersetzen wir die In-Memory-Liste durch echte SELECT-Abfragen.
==== 1. Alle Posts – ''GET /posts'' ====
// READ – alle Posts aus der DB
app.get('/posts', (req, res) => {
const sql = `
SELECT post_id, user_id, title, image_url, description, likes
FROM post
`;
db.query(sql, (err, results) => {
if (err) {
console.error('DB-Fehler bei GET /posts:', err);
return res.status(500).send('Serverfehler bei der Post-Abfrage');
}
res.status(200).json(results);
});
});
**Test mit Postman**
* Methode: ''GET''
* URL: ''http://localhost:3000/posts''
* Erwartung:
- Status ''200 OK''
- JSON-Array mit allen Zeilen aus der Tabelle ''post''
==== 2. Einzelner Post – ''GET /posts/:id'' ====
// READ – einzelner Post nach ID aus der DB
app.get('/posts/:id', (req, res) => {
const id = Number(req.params.id);
const sql = `
SELECT post_id, user_id, title, image_url, description, likes
FROM post
WHERE post_id = ?
`;
db.query(sql, [id], (err, results) => {
if (err) {
console.error('DB-Fehler bei GET /posts/:id:', err);
return res.status(500).send('Serverfehler bei der Post-Abfrage');
}
if (results.length === 0) {
return res.status(404).send('Post nicht gefunden');
}
res.status(200).json(results[0]);
});
});
===== CREATE – Neuen Post in der DB speichern =====
Jetzt bauen wir die ''POST /posts''-Route so um, dass sie **''INSERT''** in die MySQL-Tabelle ausführt.
// CREATE – neuen Post in der DB anlegen
app.post('/posts', (req, res) => {
const { user_id, title, image_url, description } = req.body;
// Einfache Validierung der Pflichtfelder
if (!user_id || !title) {
return res.status(400).send('Bitte mindestens user_id und title angeben.');
}
const sql = `
INSERT INTO post (user_id, title, image_url, description, likes)
VALUES (?, ?, ?, ?, 0)
`;
const values = [
user_id,
title,
image_url || '',
description || ''
];
db.query(sql, values, (err, result) => {
if (err) {
console.error('DB-Fehler bei POST /posts:', err);
return res.status(500).send('Serverfehler beim Erstellen des Posts');
}
// Neu erzeugte ID steht in result.insertId
const newPost = {
post_id: result.insertId,
user_id,
title,
image_url: image_url || '',
description: description || '',
likes: 0
};
res.status(201).json(newPost);
});
});
**Test mit Postman**
* Methode: ''POST''
* URL: ''http://localhost:3000/posts''
* Body (JSON):
{
"user_id": 1,
"title": "Neuer DB-Post",
"image_url": "https://example.com/post.jpg",
"description": "Dieser Post wurde in MySQL gespeichert."
}
* Erwartung:
- Status ''201 Created''
- JSON-Objekt mit neuer ''post_id''
- Eintrag ist in der Tabelle ''post'' sichtbar
===== UPDATE – Bestehenden Post ändern (PUT /posts/:id) =====
Wir implementieren jetzt ein ''UPDATE'' mit einfacher Validierung.
// UPDATE – vorhandenen Post aktualisieren
app.put('/posts/:id', (req, res) => {
const id = Number(req.params.id);
const { title, image_url, description, likes } = req.body;
// Mindestens ein Feld muss geändert werden
if (!title && !image_url && !description && likes === undefined) {
return res.status(400).send(
'Bitte mindestens eines der Felder title, image_url, description oder likes angeben.'
);
}
const sql = `
UPDATE post
SET
title = COALESCE(?, title),
image_url = COALESCE(?, image_url),
description = COALESCE(?, description),
likes = COALESCE(?, likes)
WHERE post_id = ?
`;
const values = [
title ?? null,
image_url ?? null,
description ?? null,
likes ?? null,
id
];
db.query(sql, values, (err, result) => {
if (err) {
console.error('DB-Fehler bei PUT /posts/:id:', err);
return res.status(500).send('Serverfehler beim Aktualisieren des Posts');
}
if (result.affectedRows === 0) {
return res.status(404).send('Post nicht gefunden');
}
res.status(200).send(`Post mit ID ${id} wurde aktualisiert.`);
});
});
**Hinweise zur Validierung**
* Wenn gar keine Felder im Body sind → ''400 Bad Request''
* Wenn die ID in der DB nicht existiert → ''404 Not Found''
* Bei Datenbankfehler → ''500 Internal Server Error''
===== DELETE – Post löschen (DELETE /posts/:id) =====
Zum Schluss implementieren wir ''DELETE'':
// DELETE – Post löschen
app.delete('/posts/:id', (req, res) => {
const id = Number(req.params.id);
const sql = 'DELETE FROM post WHERE post_id = ?';
db.query(sql, [id], (err, result) => {
if (err) {
console.error('DB-Fehler bei DELETE /posts/:id:', err);
return res.status(500).send('Serverfehler beim Löschen des Posts');
}
if (result.affectedRows === 0) {
return res.status(404).send('Post nicht gefunden');
}
res.status(200).send(`Post mit ID ${id} wurde gelöscht.`);
});
});
===== Zusammenfassung & Transfer auf Ihr Projekt =====
In dieser Learning Unit haben Sie:
* Ihren Express-Server mit **MySQL** verbunden (''mysql2''),
* **CRUD-Routen** für ''posts'' so erweitert, dass sie auf die echte Tabelle ''post'' zugreifen,
* einfache **Validierung** eingebaut (Pflichtfelder, leere Updates),
* sinnvolle **HTTP-Statuscodes** verwendet:
- ''201'' für erfolgreiches Erstellen,
- ''200'' für erfolgreiche Lese-/Update-/Delete-Operationen,
- ''400'' bei falschen Eingaben,
- ''404'' bei nicht gefundenen Datensätzen,
- ''500'' bei Server-/Datenbankfehlern.
**Nächster Schritt für Ihr Modulprojekt:**
* Erstellen Sie für Ihren eigenen Use Case (Reisen, Filme, Bücher, …) eine entsprechende Tabelle (oder mehrere Tabellen).
* Bauen Sie ähnliche Routen:
- ''GET /[ressource]'', ''GET /[ressource]/:id''
- ''POST /[ressource]''
- ''PUT /[ressource]/:id''
- ''DELETE /[ressource]/:id''
* Testen Sie alles mit **Postman**.
* Nutzen Sie diese Struktur als Grundlage für die LB3-Projektarbeit.
==== Vocabulary ====
^ English ^ Deutsch ^
| query | Abfrage (SQL) |
| result set | Resultatmenge (Abfrage-Ergebnis)|
| to insert | einfügen |
| to update | aktualisieren |
| to delete | löschen |
| error handling | Fehlerbehandlung |
| validation | Validierung / Eingabeprüfung |