Express.js Mastery / Express: Let’s Start Building The Natours API!

Handling PATCH Requests

πŸ“Œ Updating Existing Data

After implementing GET and POST, the next step is handling PATCH requests to update existing data.

πŸ”„ PUT vs PATCH

Method

Description

PUT

Replaces the entire resource.

PATCH

Updates only the specified fields.

βœ… Why use PATCH?

  • ✏️ Only the changed fields need to be sent.

  • πŸ‘€ Simpler for the client since they don't have to send the entire object.

  • πŸš€ This approach also works well with databases like MongoDB/Mongoose, which we'll use later.

πŸ“Œ In this course, we'll implement PATCH only.


πŸ›£οΈ Route Structure

  • 🌐 URL: api/v1/tours/:id

  • Needs the tour's ID in the URL (like the earlier GET-single-tour route) so the app knows which tour to update.


πŸ”Ή Step 1: Why the actual update logic isn't implemented

Since this app is just testing API concepts using a JSON file (not a real database), fully implementing the update would mean:

  1. πŸ“– Reading the tour from the JSON file

  2. ✏️ Modifying it

  3. πŸ’Ύ Saving the whole file back

🚫 That's unnecessary extra work for what this section is teaching.

🎯 The real focus here is:

  • 🌐 Understanding HTTP verbs (GET, POST, PATCH, DELETE)

  • πŸ”’ Understanding proper status codes (e.g., 201 for created, 200 for success, 400/404 for errors)

  • πŸ“¦ Understanding the correct response structure/format


πŸ”Ή Step 2: Writing the PATCH handler

app.patch('/api/v1/tours/:id', (req, res) => {
  if (req.params.id * 1 > tours.length) {
    return res.status(404).json({
      status: 'fail',
      message: 'Invalid ID'
    });
  }

  res.status(200).json({
    status: 'success',
    data: {
      tour: '<Updated tour here...>'
    }
  });
});

πŸ’‘ Why each part works:

  • πŸ”’ req.params.id * 1 β€” converts the string ID from the URL into a number (same trick used in the GET-single-tour route)

  • βœ… ID validation check β€” reused logic from before: if the ID is out of range, respond with 404 Not Found and a fail status

  • 🟒 200 status β€” correct code for a successful update (unlike 201, which is only for newly created resources)

  • πŸ“¦ The response still follows the same JSON envelope pattern: status + data

  • πŸ“ Since there's no real update logic, a placeholder string ('Updated tour here...') stands in for what would normally be the actual updated tour object


πŸ”Ή Step 3: Testing in Postman

  • πŸ’Ύ Save the existing Get request

  1. πŸ“‹ Duplicate the existing "Get Tour" request.

  2. πŸ”„ Change the method to PATCH.

  3. πŸ’Ύ Save it as "Update Tour" (shown in a distinct gray text in the sidebar to mark it apart from other saved requests).

  • πŸ“¦ Add a request body β†’ Body β†’ raw β†’ JSON:

image.png
{
  "duration": 15
}
  • βœ… Send it targeting tour ID 3 β†’ response returns the placeholder "Updated tour here..." with status 200.

  • ❌ Test again with an invalid ID β†’ response returns "fail" / "Invalid ID" with status 404.

  • πŸ’Ύ Save the request again so the body content persists for later use.

⚠️ Note: Since the update logic isn't implemented, sending this request doesn't actually change any data β€” it just confirms the route, status codes, and response shape work correctly.


βœ… Key Takeaway

  • 🩹 PATCH is used for partial updates (only changed fields); πŸ“¦ PUT is used for full-object replacement β€” this app uses PATCH.

  • 🟒 The response for a successful update uses status 200, not 201 (that's reserved for creation).

  • ♻️ ID validation logic from the GET-single-tour route is reused here β€” a recurring pattern for any route needing a specific tour by ID.

  • 🎯 The actual "update the file" logic is intentionally skipped since the focus is on HTTP methods, status codes, and response formatting, not file-based persistence.


⏭️ What's Next

  • πŸ—‘οΈ Only DELETE remains to complete the full CRUD set (Create, Read, Update, Delete).