Inhaltsverzeichnis

LU17 – CRUD mit Express & MySQL

Learning Objectives

Ausgangslage

In LU16 haben Sie eine kleine API für Social-Media-Posts gebaut:

Jetzt machen wir einen wichtigen Schritt in Richtung „echte“ Anwendung:

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

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

{
  "user_id": 1,
  "title": "Neuer DB-Post",
  "image_url": "https://example.com/post.jpg",
  "description": "Dieser Post wurde in MySQL gespeichert."
}

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

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:

Nächster Schritt für Ihr Modulprojekt:

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