🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Completing CRUD

Complete your CRUD API. Understand how to use Mongoose's findByIdAndUpdate and findByIdAndDelete methods, why the { new: true } flag is critical, and the architectural theory behind securing endpoints to specific document owners.

Total XP: 0|💻 mernblog XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

Select an unlocked node to view details root

🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

Let's cut the fluff. Here is exactly what you need to know about this concept to survive in a real production environment.

1Completing CRUD

Look, if you've ever dealt with this in production, you know exactly what the problem is. We have successfully implemented the 'Create' and 'Read' operations. To complete our blog's backend functionality, we must implement 'Update' and 'Delete'. However, unlike reading a public blog post, updating or deleting data is a destructive action. We must strictly control who is allowed to perform these actions. If anyone can send a DELETE /api/posts/:id request and wipe out another user's content, our application is fundamentally insecure. This isn't just academic theory—understanding the *why* behind this is what separates junior devs from senior engineers. When you deploy a full-stack JavaScript app, this is the mechanic that prevents catastrophic failure.

+
/* The Security Requirement */
GET  /api/posts       -> Public (Anyone can read)
POST /api/posts       -> Protected (Must be logged in)
PUT  /api/posts/:id   -> Protected (Must be AUTHOR)
DEL  /api/posts/:id   -> Protected (Must be AUTHOR)
localhost:3000
localhost:3000 (MERN App)
[Completing CRUD] Output:

Component rendered successfully.
API data fetched via Express.

2The Update Endpoint

Look, if you've ever dealt with this in production, you know exactly what the problem is. To update a document, we use a PUT or PATCH HTTP request. In Mongoose, we use findByIdAndUpdate(). This method takes three arguments: the ID of the document to find, an object containing the new data to apply, and an options object. A critical option to include is { new: true }. By default, Mongoose returns the old, outdated document *before* the update was applied. Setting new: true forces Mongoose to return the freshly updated document back to the React client. This isn't just academic theory—understanding the *why* behind this is what separates junior devs from senior engineers. When you deploy a full-stack JavaScript app, this is the mechanic that prevents catastrophic failure.

+
router.put('/:id', async (req, res) => {
  try {
    // 1. ID to find, 2. Data to update, 3. Options
    const updatedPost = await Post.findByIdAndUpdate(
      req.params.id,
      req.body,
      { new: true }
    );
    res.status(200).json(updatedPost);
  } catch (err) {
    res.status(500).json(err);
  }
});
localhost:3000
localhost:3000 (MERN App)
[The Update Endpoint] Output:

Component rendered successfully.
API data fetched via Express.

3The Delete Endpoint

Look, if you've ever dealt with this in production, you know exactly what the problem is. Deleting a document is relatively straightforward using Mongoose's findByIdAndDelete(). When a DELETE request hits /api/posts/:id, Express extracts the id from the URL parameters and passes it to Mongoose. If the document is found and deleted, Mongoose returns the deleted document. If the document does not exist (perhaps it was already deleted), it returns null. We must check for this null state and return a 404 Not Found to the client if necessary. This isn't just academic theory—understanding the *why* behind this is what separates junior devs from senior engineers. When you deploy a full-stack JavaScript app, this is the mechanic that prevents catastrophic failure.

+
router.delete('/:id', async (req, res) => {
  try {
    const post = await Post.findByIdAndDelete(req.params.id);
    if (!post) {
      return res.status(404).json("Post not found");
    }
    res.status(200).json("Post deleted successfully");
  } catch (err) {
    res.status(500).json(err);
  }
});
localhost:3000
localhost:3000 (MERN App)
[The Delete Endpoint] Output:

Component rendered successfully.
API data fetched via Express.

4Enforcing Authorization

Look, if you've ever dealt with this in production, you know exactly what the problem is. Currently, our endpoints are fully functional, but dangerously exposed. Anyone with Postman can send a DELETE request to /api/posts/123 and destroy the database. To fix this, we must enforce Authorization at the route level. Before we call findByIdAndUpdate, we must first check if post.author.toString() === req.user.id. We will build out this req.user functionality in the upcoming Authentication module using JSON Web Tokens (JWT). This isn't just academic theory—understanding the *why* behind this is what separates junior devs from senior engineers. When you deploy a full-stack JavaScript app, this is the mechanic that prevents catastrophic failure.

+
router.delete('/:id', async (req, res) => {
  const post = await Post.findById(req.params.id);
  
  // SECURITY CHECK: Is the person making the request
  // the actual author of the post?
  if (post.author.toString() !== req.user.id) {
    return res.status(401).json("Not authorized");
  }
  
  await post.deleteOne();
});
localhost:3000
localhost:3000 (MERN App)
[Enforcing Authorization] Output:

Component rendered successfully.
API data fetched via Express.

5The Stage is Set

Look, if you've ever dealt with this in production, you know exactly what the problem is. We have now explored the theoretical architecture for secure CRUD operations. However, to actually implement these security guards, we need a robust identity system. How does the server know who req.user is? Since HTTP is completely stateless, the server forgets who you are the millisecond the request finishes. In the next module, we will solve this fundamental problem using JSON Web Tokens (JWT) and secure authentication. This isn't just academic theory—understanding the *why* behind this is what separates junior devs from senior engineers. When you deploy a full-stack JavaScript app, this is the mechanic that prevents catastrophic failure.

+
/* Security Required */
.curriculum { next: 'jwt_authentication'; }
localhost:3000
localhost:3000 (MERN App)
[The Stage is Set] Output:

Component rendered successfully.
API data fetched via Express.

6Step-by-Step Breakdown

Completing CRUD. We have successfully implemented the 'Create' and 'Read' operations. To complete our blog's backend functionality, we must implement 'Update' and 'Delete'. However, unlike reading a public blog post, updating or deleting data is a destructive action. We must strictly control who is allowed to perform these actions. If anyone can send a DELETE /api/posts/:id request and wipe out another user's content, our application is fundamentally insecure.

The Update Endpoint. To update a document, we use a PUT or PATCH HTTP request. In Mongoose, we use findByIdAndUpdate(). This method takes three arguments: the ID of the document to find, an object containing the new data to apply, and an options object. A critical option to include is { new: true }. By default, Mongoose returns the old, outdated document *before* the update was applied. Setting new: true forces Mongoose to return the freshly updated document back to the React client.

When using the Mongoose findByIdAndUpdate method to process a PUT request, why is it highly recommended to pass { new: true } as the third options argument?

  • It returns the freshly updated document.
  • It creates a duplicate document.

The Delete Endpoint. Deleting a document is relatively straightforward using Mongoose's findByIdAndDelete(). When a DELETE request hits /api/posts/:id, Express extracts the id from the URL parameters and passes it to Mongoose. If the document is found and deleted, Mongoose returns the deleted document. If the document does not exist (perhaps it was already deleted), it returns null. We must check for this null state and return a 404 Not Found to the client if necessary.

Enforcing Authorization. Currently, our endpoints are fully functional, but dangerously exposed. Anyone with Postman can send a DELETE request to /api/posts/123 and destroy the database. To fix this, we must enforce Authorization at the route level. Before we call findByIdAndUpdate, we must first check if post.author.toString() === req.user.id. We will build out this req.user functionality in the upcoming Authentication module using JSON Web Tokens (JWT).

Before executing a destructive database operation like a delete, why is it necessary to fetch the document first, rather than immediately running findByIdAndDelete()?

  • To examine the author field and verify ownership before deletion.
  • Because Mongoose requires documents in RAM to delete them.

The Stage is Set. We have now explored the theoretical architecture for secure CRUD operations. However, to actually implement these security guards, we need a robust identity system. How does the server know who req.user is? Since HTTP is completely stateless, the server forgets who you are the millisecond the request finishes. In the next module, we will solve this fundamental problem using JSON Web Tokens (JWT) and secure authentication.

Level Up 🚀

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

Fully supported.

Accessibility (A11y)

1Semantic Usage

Using the proper structure for Completing CRUD ensures that screen readers can correctly interpret the content hierarchy and purpose.

<!-- Apply semantic elements appropriately -->

SEO Implications

  • 1

    Contextual Relevance

    Proper implementation of Completing CRUD provides search engine crawlers with better context, improving the indexing accuracy of your page.

Best Practices

Clean Code

Always validate your structure when using Completing CRUD to prevent layout shifts and DOM inconsistencies.

Separation of Concerns

Keep styling and behavior separate from the structural markup of Completing CRUD.

Frequent Bugs

THE BUG

Unexpected layout shifts or styling failures.

THE FIX

Ensure all implementations related to Completing CRUD are properly structured according to strict specifications.

Real-World Examples

Production Usage

Here is how Completing CRUD is typically implemented in a professional, robust application.

<!-- Best practice implementation of Completing CRUD -->
<div class="production-ready">
  <!-- Content -->
</div>

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Not reading error messages carefully

Uncaught TypeError: Cannot read properties of undefined (reading 'length') // Solution: Ensure the variable you are calling .length on is initialized as a string or an array, not undefined.

The Solution //

Most of the time, the compiler or interpreter tells you exactly what line caused the crash and why. Read stack traces from the top down to identify the root cause.

The Error //

Hardcoding sensitive credentials

// Wrong const API_KEY = 'sk-123456789'; // Correct const API_KEY = process.env.API_KEY;

The Solution //

Never hardcode API keys, passwords, or secrets in your source code. Use environment variables (.env files) to keep them secure and out of version control.

Continue Learning