Home > Net >  Node.js / MongoDB - TypeError: Cannot destructure property 'title' of 'req.body'
Node.js / MongoDB - TypeError: Cannot destructure property 'title' of 'req.body'

Time:06-26

I am preparing a project for an interview where I need to build an app to display videos to logged in users. I've started working on the back-end (in Node.js / Express / TypeScript / Mongoose / MongoDB). Everything worked until I tested posting data in Thunder Client; I got this error message:

TypeError: Cannot destructure property 'title' of 'req.body' as it is undefined.
    at createVideo (/home/wilder/Bureau/video-streaming-server/src/controllers/Video.ts:8:5)
    at Layer.handle [as handle_request] (/home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/route.js:144:13)
    at Route.dispatch (/home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/route.js:114:3)
    at Layer.handle [as handle_request] (/home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/layer.js:95:5)
    at /home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/index.js:284:15
    at Function.process_params (/home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/index.js:346:12)
    at next (/home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/index.js:280:10)
    at Function.handle (/home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/index.js:175:3)
    at router (/home/wilder/Bureau/video-streaming-server/node_modules/express/lib/router/index.js:47:12)

I know very similar questions have been asked (and answered here) but I cannot make it work still. As I gathered from said questions and answers, the content of req.body is, by default, undefined, hence I tried using

app.use(express.json());

but it doesn't change anything.

Here is my code so far:

src/Server.ts

import express from "express";
import http from "http";
import mongoose from "mongoose";
import { config } from "./config/config";
import videoRoutes from "./routes/Video";

const router = express();

// Connect to MongoDB
mongoose
  .connect(config.mongo.url, { retryWrites: true, w: "majority" })
  .then(() => {
    console.log("Connected to MongoDB.");
    startServer();
  })
  .catch((err) => {
    console.log(err);
  });

// Start server (only if MongoDB connects)
const startServer = () => {
  // Routes
  router.use("/videos", videoRoutes);

  // Error handling
  router.use((req, res) => {
    const err = new Error("not found");
    console.error(err);

    return res.status(404).json({ message: err.message });
  });

  // Server running
  http
    .createServer(router)
    .listen(config.server.port, () =>
      console.log(`Server is running on port ${config.server.port}.`)
    );
};

src/models/Video.ts

import mongoose, { Document, Schema } from "mongoose";

export interface IVideo {
  title: string;
  description: string;
  video_path: string;
  tags: string[];
  duration: string;
  views: string;
  creator: string;
  created_at: string;
  like: number;
  dislike: number;
  comments: [
    {
      user: string;
      text: string;
      date: string;
    }
  ];
}

const VideoSchema: Schema = new Schema(
  {
    title: { type: String, required: true },
    description: { type: String, required: true },
    video_path: { type: String, required: true },
    tags: { type: Array, required: true },
    duration: { type: String, required: true },
    views: { type: String, required: true },
    creator: { type: String, required: true },
    created_at: { type: String, required: true },
    like: { type: Number, required: true },
    dislike: { type: Number, required: true },
    comments: [
      {
        user: { type: String, required: true },
        text: { type: String, required: true },
        date: { type: String, required: true },
      },
    ],
  },
  { versionKey: false }
);

export default mongoose.model<IVideo>("Video", VideoSchema);

src/controllers/Video.ts

import { NextFunction, Request, Response } from "express";
import mongoose, { Mongoose } from "mongoose";
import Video from "../models/Video";

// Create video
const createVideo = (req: Request, res: Response, next: NextFunction) => {
  const {
    title,
    description,
    video_path,
    tags,
    duration,
    views,
    creator,
    created_at,
    like,
    dislike,
    comments,
    user,
    text,
    date,
  } = req.body;

  const video = new Video({
    _id: new mongoose.Types.ObjectId(),
    title,
    description,
    video_path,
    tags,
    duration,
    views,
    creator,
    created_at,
    like,
    dislike,
    comments,
    user,
    text,
    date,
  });

  return video
    .save()
    .then((video) => res.status(201).json({ video }))
    .catch((err) => res.status(500).json({ err }));
};

// Get a single video
const readVideo = (req: Request, res: Response, next: NextFunction) => {
  const videoId = req.params.videoId;

  return Video.findById(videoId)
    .then((video) =>
      video
        ? res.status(200).json({ video })
        : res.status(404).json({ message: "Not found." })
    )
    .catch((err) => res.status(500).json({ err }));
};

// Get all videos
const readAll = (req: Request, res: Response, next: NextFunction) => {
  return Video.find()
    .then((videos) => res.status(200).json({ videos }))
    .catch((err) => res.status(500).json({ err }));
};

// Update video
const updateVideo = (req: Request, res: Response, next: NextFunction) => {
  const videoId = req.params.videoId;

  return Video.findById(videoId)
    .then((video) => {
      if (video) {
        video.set(req.body);

        return video
          .save()
          .then((video) => res.status(201).json({ video }))
          .catch((err) => res.status(500).json({ err }));
      } else {
        res.status(404).json({ message: "Not found." });
      }
    })
    .catch((err) => res.status(500).json({ err }));
};

// Delete video
const deleteVideo = (req: Request, res: Response, next: NextFunction) => {
  const videoId = req.params.videoId;

  return Video.findByIdAndDelete(videoId)
    .then((video) =>
      video
        ? res.status(201).json({ message: "Deleted." })
        : res.status(404).json({ message: "Not found." })
    )
    .catch((err) => res.status(500).json({ err }));
};

export default {
  createVideo,
  readVideo,
  readAll,
  updateVideo,
  deleteVideo,
};

src/routes/Video.ts

import express from "express";
import controller from "../controllers/Video";

const app = express();
const router = express.Router();

app.use(express.json());

router.post("/create", controller.createVideo);
router.get("/get/:videoId", controller.readVideo);
router.get("/get/", controller.readAll);
router.patch("/update/:videoId", controller.updateVideo);
router.delete("/delete/:videoId", controller.deleteVideo);

export = router;

And here is the format of data I need to add in my database

{
    "title": "Rotating planet",
    "description": "Vidéo de la planète en train de tourner",
    "video": "/video_example.mp4",
    "tags": ["planet", "earth", "science", "space"],
    "duration": "00:31",
    "views": 19876,
    "creator": "ThePlanetGuy",
    "created_at": "2021-05-01T08:00:00.00Z",
    "like": 10,
    "dislike": 2,
    "comments": [{
        "user": "Anonymous",
        "text": "Beautiful",
        "date": "2021-05-10T08:00:00.00Z"
    }, {
        "user": "Flatter",
        "text": "Fake ! The earth is flat !",
        "date": "2021-05-05T10:00:00.00Z"
    }]
}

If anyone could help me understand what I did wrong, I would gladly appreciate it. I am still very new to programming, especially back-end.

Thank you :)

CodePudding user response:

In src/routes/Video.ts, you're creating a new Express app for adding the JSON parser middleware to, but you don't do anything with that app.

Instead, either add the middleware to the router instance:

router.use(express.json());

Or add it to the main Express app that is created in src/Server.ts

  • Related