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:
Headers and other data I used are:
The things which I observed are:
-
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. -
The error message doesn’t show any particular line of written code so it is hard to figure out where the actual issue lies.
-
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.
3
Answers
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:app.use(express.urlencoded({extended: false}));
app.use(express.json());
app.use(morgan('dev'));
app.use(cookieParser());
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
.After installing this, I also fixed the syntax(old) with new i.e.
filepath
andmimetype
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.
Remove middleware app.use(express.urlencoded({extended: false}));
app.use(express.json())
And
app.use(cookieParser())
From server.js and then try
While you are sending data using form data. You set
Content-Type: application/json
wrong.Set
Content-Type: multipart/form-data