Wat ga je maken?

Je hebt CREATE (POST) en READ (GET). Tijd voor de laatste twee CRUD operaties:

  • UPDATE - Bestaande workout aanpassen (bijv. reps van 10 naar 15)
  • DELETE - Workout verwijderen uit database

HTTP Methodes voor UPDATE

Twee methodes om data aan te passen:

PUT - Vervang hele object (moet ALLE velden meesturen)
PATCH - Pas alleen bepaalde velden aan (stuur alleen wat je wilt veranderen)

Wij gebruiken PATCH omdat dat makkelijker is: je hoeft niet hele object te sturen, alleen velden die je wilt aanpassen.

PATCH - Workout Aanpassen (UPDATE)

Functie die bestaande workout kan aanpassen.

Wat moet functie doen?

  1. Check of ID geldig is (anders crasht app)
  2. Zoek workout in database
  3. Bestaat niet? Stuur 404 error
  4. Bestaat wel? Pas aan met nieuwe data
  5. Stuur aangepaste workout terug

Controller functie

Voeg toe aan src/controllers/workoutController.js:

// PATCH workout (aanpassen)
export const updateWorkout = async (req, res) => {
  const { id } = req.params;

  // Check of ID geldig is
  if (!mongoose.isValidObjectId(id)) {
    return res.status(400).json({ error: 'Ongeldige workout ID' });
  }

  try {
    const workout = await Workout.findByIdAndUpdate(
      id, 
      { ...req.body },
      { new: true }
    );

    if (!workout) {
      return res.status(404).json({ error: 'Workout niet gevonden' });
    }

    res.status(200).json(workout);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
};
Regel voor regel:
  • const { id } = req.params - Haal ID uit URL
  • isValidObjectId(id) - Check ID formaat
  • findByIdAndUpdate() - Zoek en pas aan
  • { ...req.body } - Neem alle velden uit body (spread operator)
  • { new: true } - Geef NIEUWE versie terug (niet oude)
  • if (!workout) - Niet gevonden? Stuur 404

Wat is { ...req.body }?

Dit is de spread operator. Pakt alle velden uit req.body en zet in object.

Voorbeeld:

Als body is:

{
  "reps": 15,
  "load": 60
}

Wordt { ...req.body } dit:

{ reps: 15, load: 60 }

MongoDB past dan alleen deze twee velden aan. title blijft onveranderd!

Wat is { new: true }?

Standaard geeft findByIdAndUpdate() de oude versie terug (van vóór aanpassing). Met { new: true } krijg je nieuwe versie (ná aanpassing).

Voorbeeld zonder { new: true }:

Je past reps aan van 10 → 15
Response geeft: "reps": 10 (oude waarde!)

Met { new: true }:

Response geeft: "reps": 15 (nieuwe waarde!)

DELETE - Workout Verwijderen

Functie die workout uit database verwijdert.

Wat moet functie doen?

  1. Check of ID geldig is
  2. Zoek en verwijder workout in één stap
  3. Bestaat niet? Stuur 404 error
  4. Succesvol verwijderd? Stuur verwijderde workout terug (zodat je ziet wat weg is)

Controller functie

Voeg toe aan src/controllers/workoutController.js:

// DELETE workout (verwijderen)
export const deleteWorkout = async (req, res) => {
  const { id } = req.params;

  // Check of ID geldig is
  if (!mongoose.isValidObjectId(id)) {
    return res.status(400).json({ error: 'Ongeldige workout ID' });
  }

  try {
    const workout = await Workout.findByIdAndDelete(id);

    if (!workout) {
      return res.status(404).json({ error: 'Workout niet gevonden' });
    }

    res.status(200).json(workout);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
};
Regel voor regel:
  • const { id } = req.params - Haal ID uit URL
  • isValidObjectId(id) - Check ID formaat
  • findByIdAndDelete(id) - Zoek en verwijder in één keer
  • if (!workout) - Niet gevonden? Stuur 404
  • res.status(200).json(workout) - Stuur verwijderde workout als bevestiging

Waarom verwijderde workout terugsturen?

Handig om te zien wat er is verwijderd. In frontend kun je melding tonen: "Workout 'Squats' is verwijderd". Zonder data weet je alleen: "er is iets verwijderd", maar niet wat.

Kan je verwijderde workout terughalen?

Nee! Als je findByIdAndDelete() hebt uitgevoerd, is workout permanent weg. Geen "undo" knop. Daarom slim om bevestiging te vragen in frontend: "Weet je zeker dat je wilt verwijderen?"

Routes Toevoegen

Twee nieuwe controller functies, nu routes toevoegen.

Update workoutRoutes.js

Vervang volledige inhoud van src/routes/workoutRoutes.js:

// src/routes/workoutRoutes.js
import express from 'express';
import { 
  getAllWorkouts, 
  getWorkoutById, 
  createWorkout,
  updateWorkout,
  deleteWorkout
} from '../controllers/workoutController.js';

const router = express.Router();

// GET alle workouts
router.get('/', getAllWorkouts);

// GET één workout
router.get('/:id', getWorkoutById);

// POST nieuwe workout
router.post('/', createWorkout);

// PATCH workout (aanpassen)
router.patch('/:id', updateWorkout);

// DELETE workout
router.delete('/:id', deleteWorkout);

export default router;

CRUD is compleet!

Alle 4 basis operaties:

  • Create - POST
  • Read - GET (alle + één)
  • Update - PATCH
  • Delete - DELETE

Testen in Postman

Tijd om UPDATE en DELETE routes te testen!

Voorbereiding: Test data

Zorg dat je paar workouts in database hebt. Doe POST requests als je geen data hebt.

1. PATCH - Pas workout aan

Kopieer _id van bestaande workout (doe GET om ID's te zien).

PATCH http://localhost:4000/api/workouts/abc123...
Body (raw, JSON):
{
  "reps": 20
}

Wat gebeurt er? Alleen reps wordt aangepast naar 20. Title en load blijven.

Response (status 200):

{
  "_id": "abc123...",
  "title": "Squats",
  "reps": 20,           // Aangepast!
  "load": 50,
  "createdAt": "2024-11-22T10:00:00.000Z",
  "updatedAt": "2024-11-22T15:30:00.000Z"  // Nieuwe tijd!
}

Let op: updatedAt is automatisch aangepast!

2. PATCH - Meerdere velden

PATCH http://localhost:4000/api/workouts/abc123...
Body (raw, JSON):
{
  "reps": 15,
  "load": 75,
  "title": "Heavy Squats"
}

Nu worden alle drie velden aangepast!

3. PATCH - Ongeldig ID

PATCH http://localhost:4000/api/workouts/123
Body (raw, JSON):
{
  "reps": 20
}

Response (status 400):

{
  "error": "Ongeldige workout ID"
}

4. PATCH - Niet-bestaand ID

PATCH http://localhost:4000/api/workouts/507f1f77bcf86cd799439011
Body (raw, JSON):
{
  "reps": 20
}

Response (status 404):

{
  "error": "Workout niet gevonden"
}

5. DELETE - Verwijder workout

Kopieer _id van workout die je wilt verwijderen.

DELETE http://localhost:4000/api/workouts/abc123...

Let op: DELETE heeft geen body! Alleen URL met ID.

Response (status 200):

{
  "_id": "abc123...",
  "title": "Squats",
  "reps": 10,
  "load": 50,
  "createdAt": "2024-11-22T10:00:00.000Z",
  "updatedAt": "2024-11-22T10:00:00.000Z"
}

Dit is de workout die je net verwijderde (als bevestiging).

6. DELETE - Check of echt weg

Doe GET naar zelfde ID:

GET http://localhost:4000/api/workouts/abc123...

Response (status 404):

{
  "error": "Workout niet gevonden"
}

Perfect! Workout is écht verwijderd uit database.

7. DELETE - Ongeldig ID

DELETE http://localhost:4000/api/workouts/123

Response (status 400):

{
  "error": "Ongeldige workout ID"
}

Problemen oplossen

❌ PATCH geeft oude waarde terug

Probleem: { new: true } vergeten

Check updateWorkout functie:

const workout = await Workout.findByIdAndUpdate(
  id, 
  { ...req.body },
  { new: true }  // Deze regel!
);

Zonder krijg je oude versie van voor update.

❌ PATCH verandert niets, geen error

Probleem: Geen body mee, of verkeerde veldnamen

Check:

  • Postman: Body → raw → JSON geselecteerd?
  • JSON syntax: aanhalingstekens rond veldnamen?
  • Veldnamen: "reps" (correct) of "rep" (fout)?
  • Correcte body:
    {
      "reps": 20,
      "load": 60
    }

❌ DELETE geeft 404 maar workout bestaat

Probleem: Verkeerd ID gekopieerd of spatie erin

Check:

  • Doe GET /api/workouts om alle ID's te zien
  • Kopieer _id precies (zonder spaties)
  • Test met GET /api/workouts/:id of ID werkt voor DELETE

❌ "Cannot read property 'reps' of null"

Probleem: findByIdAndUpdate() vindt niks (geeft null), maar code probeert iets te doen met null

Check if (!workout) check:

const workout = await Workout.findByIdAndUpdate(...);

if (!workout) {  // Deze check!
  return res.status(404).json({ error: 'Workout niet gevonden' });
}

res.status(200).json(workout);

❌ PATCH/DELETE werkt niet in browser

Probleem: Browsers kunnen alleen GET via adresbalk

Oplossing: Gebruik Postman voor PATCH en DELETE. Je kunt ze niet testen in browser adresbalk.

Verschil PATCH vs PUT

Je gebruikt PATCH, maar wat is verschil met PUT?

PATCH - Gedeeltelijke update

Stuur alleen velden die je wilt veranderen:

{
  "reps": 20
}

Resultaat: Alleen reps verandert. title en load blijven.

PUT - Volledige vervanging

Moet hele object sturen:

{
  "title": "Squats",
  "reps": 20,
  "load": 50
}

Als je veld vergeet (bijv. load), wordt dat veld leeg of verwijderd!

Welke gebruiken we?

We gebruiken PATCH omdat dat makkelijker is voor frontend. Je hoeft niet steeds alle velden mee te sturen, alleen wat je wilt veranderen.

PUT wordt gebruikt als je écht hele object wilt vervangen, maar dat is zelden nodig.

Checklist

✅ Check of je hebt:

  • updateWorkout functie in workoutController.js
  • updateWorkout gebruikt findByIdAndUpdate() met { new: true }
  • updateWorkout heeft ID validatie en 404 check
  • deleteWorkout functie in workoutController.js
  • deleteWorkout gebruikt findByIdAndDelete()
  • deleteWorkout heeft ID validatie en 404 check
  • Beide geëxporteerd met export const
  • PATCH route: router.patch('/:id', updateWorkout)
  • DELETE route: router.delete('/:id', deleteWorkout)
  • PATCH werkt in Postman en past alleen meegegeven velden aan
  • DELETE werkt in Postman en verwijdert écht
  • Beide routes geven correcte errors bij ongeldig/niet-bestaand ID
  • Je begrijpt verschil tussen PATCH en PUT

CRUD Status:

  • Create - POST nieuwe workout
  • Read - GET alle + GET één
  • Update - PATCH workout aanpassen
  • Delete - DELETE workout verwijderen

Je backend is nu klaar! Volledige REST API met alle CRUD operaties.

Volgende Stap

Backend API is compleet met alle CRUD operaties! Kies nu hoe je je frontend wilt verbinden:

Frontend verbinden met HTML/CSS/JS →

Verbind je backend met een gewone HTML/CSS/JavaScript frontend

Frontend verbinden met React →

Verbind je backend met een React frontend