node.jsmongodbexpressformidable

formidable - SyntaxError: Unexpected token - in JSON at position 0 when sending POST request


I am building the backend for creating blog posts for my web application while following a tutorial.

The technologies I am using are MongoDB, express.js, formidable

The relevant files are:

server.js

......

// middlewares
app.use(express.urlencoded({extended: false}));
app.use(express.json());

app.use(morgan('dev'));
app.use(cookieParser());

// cors
if(process.env.NODE_ENV == 'development') {
    app.use(cors({origin: `${process.env.CLIENT_URL}`}));
}

// routes middleware
app.use('/api', authRoutes);
app.use('/api', userRoutes);
app.use('/api', blogRoutes);
app.use('/api', categoryRoutes);
app.use('/api', tagRoutes);

// port
const port = process.env.PORT || 8000;

// Listening App
app.listen(port, () => {
    console.log(`Server is running on PORT ${port}`);
})

Blog Schema Model:

const mongoose = require('mongoose');
const { ObjectId } = mongoose.Schema;

const blogSchema = new mongoose.Schema(
    {
        title: {
            type: String,
            trim: true,
            min: 3,
            max: 160,
            required: true
        },
        slug: {
            type: String,
            unique: true,
            index: true
        },
        body: {
            type: {},
            required: true,
            min: 200,
            max: 2000000
        },
        excerpt: {
            type: String,
            max: 1000
        },
        mtitle: {
            type: String
        },
        mdesc: {
            type: String
        },
        photo: {
            data: Buffer,
            contentType: String
        },
        categories: [{ type: ObjectId, ref: 'Category', required: true }],
        tags: [{ type: ObjectId, ref: 'Tag', required: true }],
        postedBy: {
            type: ObjectId,
            ref: 'User'
        }
    },
    { timestamp: true }
);

module.exports = mongoose.model('Blog', blogSchema);

blog.js (Routes)

const express = require('express');
const router = express.Router();
const { create } = require('../controllers/blog');

const { requireSignin, adminMiddleware } = require('../controllers/auth');

router.post('/blog', requireSignin, adminMiddleware, create);

module.exports = router;

blog.js (controllers)

const Blog = require('../models/blog');
const Category = require('../models/category');
const Tag = require('../models/tag');
const formidable = require('formidable');
const slugify = require('slugify');
const stripHtml = require('string-strip-html');
const _ = require('lodash');
const { errorHandler } = require('../helpers/dbErrorHandler');
const fs = require('fs');

exports.create = (req, res) => {
    let form = new formidable.IncomingForm();
    form.keepExtensions = true;
    form.parse(req, (err, fields, files) => {
        if (err) {
            return res.status(400).json({
                error: 'Image could not upload'
            });
        }

        const { title, body, categories, tags } = fields;

        let blog = new Blog();
        blog.title = title;
        blog.body = body;
        blog.slug = slugify(title).toLowerCase();
        blog.mtitle = `${title} | ${process.env.APP_NAME}`;
        blog.mdesc = stripHtml(body.substring(0, 160));
        blog.postedBy = req.user._id;

        if (files.photo) {
            if (files.photo.size > 10000000) {
                return res.status(400).json({
                    error: 'Image should be less then 1mb in size'
                });
            }
            blog.photo.data = fs.readFileSync(files.photo.path);
            blog.photo.contentType = files.photo.type;
        }

        blog.save((err, result) => {
            if (err) {
                return res.status(400).json({
                    error: errorHandler(err)
                });
            }
            res.json(result);
        });
    });
};

Problem: When I POST a request using Postman in order to create a category which is as follows: Posting Request

Headers and other data I used are: Request Headers

I am getting this error: Main Error

The things which I observed are:

  1. As I am following a particular tutorial, the formidable versions might be updated, hence the syntax error. Still, I wasn't able to find any particular solutions for handling IncomingForm() using formidable.

  2. The error message doesn't show any particular line of written code so it is hard to figure out where the actual issue lies.

  3. I have checked my blog schema model definition and it looks fine couldn't figure out anything wrong there.

Currently, I am unable to find a solution to this issue as I may be unaware of any minor mistakes I may have committed.

I have attached all my relevant files and I can produce any other files if needed.

I request you to please go through my issue as I am stuck here and couldn't proceed further.

Thanks.


Solution

  • Refer to this answer if anyone encounters this error in the future.

    The above answers may be applicable to any other situations so must try them too.

    My Fix:

    I was using formidable version 2.0.1 along with the app middleware as follows:

    I have found out that formidable doesn't work with these above middleware and it is not possible to POST images using formidable.

    My Solution: I found out about express-formidable.

    npm install express-formidable
    

    After installing this, I also fixed the syntax(old) with new i.e.

    blog.photo.data = fs.readFileSync(files.photo.filepath);
    blog.photo.contentType = files.photo.mimetype;
    

    filepath and mimetype

    After this, when I tested it with postman, I also set the Content-Type to default (checked the hidden header which is default) and it worked nicely.