I've created a simple RESTapi with express and for file upload I'm using multer. Creating a new item / post works. My issue is with the put route and the function to handle saving and updating the post/gear.
When the product image field is left blank, it returns
undefined [Object: null prototype] {
title: 'joey',
price: '123',
weight: '123',
description: 'lorem'
}
(node:5293) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'path' of undefined
at /Users/Zack/Desktop/LeFIAT/lefiatV2/routes/gear.js:81:34
When all the fields in the product fields are filled out returns a duplicate key
MongoServerError: E11000 duplicate key error collection: lefiatv2.products index: slug_1 dup key: { slug: "joey" }
at /Users/Zack/Desktop/LeFIAT/lefiatV2/node_modules/mongodb/lib/operations/update.js:80:33
The object is being populated I just can't seem to find the correct path or set up for the function
{
fieldname: 'image',
originalname: 'TorridV2_Toggle__.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: './public/products/',
filename: '2022-02-02T15:44:30.813ZTorridV2_Toggle__.jpg',
path: 'public/products/2022-02-02T15:44:30.813ZTorridV2_Toggle__.jpg',
size: 23382
} [Object: null prototype] {
title: 'joey',
price: '123',
weight: '123',
description: 'lorem'
}
edit.ejs
Edit Product
<form action="/gear/<%= product.slug %>?_method=PUT" method="POST" enctype="multipart/form-data">
<%- include('../partials/product_fields') %>
</form>
product_fields.ejs
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" id="title" class="form-control" value="<%= product.title %>" required>
</div>
<div class="form-group">
<label for="price">Price</label>
<input type="number" min="1" step="0.01" name="price" id="price" class="form-control"
required><%= product.price %></input>
</div>
<div class="form-group">
<label for="weight">Weight</label>
<input type="number" min="1" step="0.01" name="weight" id="weight" class="form-control"
required><%= product.weight %></input>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" id="description" class="form-control" required><%= product.description %></textarea>
</div>
<div class="form-group">
<label for="image">Upload Images</label>
<input type="file" name="image" id="image" class="form-control-file" multiple>
</div>
Cancel
<button type="submit" class="btn btn-primary"> Save </button>
product.js modal
const { date } = require('joi')
const mongoose = require('mongoose')
const slugify = require('slugify')
const productSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
price: {
type: Number,
required: true
},
weight: {
type: Number,
required: true,
},
slug: {
type: String,
required: true,
unique: true
},
createdAt: {
type: Date,
default:Date.now
},
image: {
type: String,
data: Buffer
}
})
productSchema.pre('validate', function(next) {
if (this.title) {
this.slug = slugify(this.title, { lower: true, strict: true })
}
next()
})
module.exports = mongoose.model('Product', productSchema)
gear.js route
const express = require('express')
const multer = require('multer')
const Product = require('./../models/product')
const router = express.Router()
const storage = multer.diskStorage({
// destination for file
destination: function (req, file, callback) {
callback(null, './public/products/')
},
// add back the extension
filename: function (req, file, callback) {
callback(null, new Date().toISOString() + file.originalname)
},
})
const fileFilter = (req, file, cb) => {
// reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
}
};
// upload parameters for multer
const upload = multer({
storage: storage,
limits: {
fileSize: 1024*1024*3,
},
fileFilter: fileFilter
})
router.get('/', async (req, res) => {
const products = await Product.find().sort({ createdAt: 'desc' })
res.render('gear/index', { products: products })
})
router.get('/new', (req, res) => {
res.render('gear/new', { product: new Product() })
})
router.get('/edit/:id', async (req, res) => {
const product = await Product.findById(req.params.id)
res.render('gear/edit', { product: product })
})
router.get('/:slug', async (req, res) => {
const product = await Product.findOne({ slug: req.params.slug })
if(product == null) res.redirect('/gear')
else res.render('gear/show', { product: product })
})
router.post('/', upload.single('image'), async (req, res, next) => {
req.product = new Product()
next()
}, saveProductAndRedirect('new'))
router.put('/:id', upload.single('image'), async (req, res, next) => {
console.log(req.file, req.body)
req.product = await Product.findOneAndUpdate({ slug: req.params.slug })
next()
}, saveProductAndRedirect(`edit`))
router.delete('/:id', async (req, res) => {
await Product.findByIdAndDelete(req.params.id)
res.redirect(`/gear`)
})
function saveProductAndRedirect(path) {
return async (req, res) => {
let product = req.product
product.title = req.body.title
product.description = req.body.description
product.price = req.body.price
product.weight = req.body.weight
product.image = req.file.path
try {
if (! req.file || ! req.file.path) {
return res.sendStatus(400);
}
product = await product.save()
res.redirect(`/gear/${product.slug}`)
} catch(err) {
console.log(err)
res.render(`gear/${path}`, { product: product })
}
}
}
module.exports = router
server.js
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config()
}
const express = require('express')
const path = require('path');
const ejsMate = require('ejs-mate');
const session = require('express-session');
const methodOverride = require('method-override');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const mongoSanitize = require('express-mongo-sanitize');
const expressLayouts = require('express-ejs-layouts')
const ExpressError = require('./utils/ExpressError');
const indexRouter = require('./routes/index')
const tripsRouter = require('./routes/trips')
const gearRouter = require('./routes/gear')
const aboutRouter = require('./routes/about')
const blogRouter = require('./routes/blog')
const app = express()
app.engine('ejs', ejsMate)
app.set('view engine', 'ejs')
app.set('views', __dirname + '/views')
app.use('/public', express.static(__dirname + '/public'));
app.use(express.urlencoded({ extended: false }));
app.use(methodOverride('_method'));
app.set('layout', 'layouts/layout')
app.use(expressLayouts)
app.use(express.static(path.join(__dirname, 'public')))
app.use(mongoSanitize({
replaceWith: '_'
}))
const MongoDBStore = require('connect-mongo')(session)
const mongoose = require('mongoose')
mongoose.connect(process.env.DATABASE_URL, {
useNewUrlParser: true })
const db = mongoose.connection
db.on('error', error => console.error(error))
db.once('open', () => console.log('Connected to Mongoose'))
const secret = process.env.SECRET || 'thisshouldbeabettersecret!';
const dbUrl = process.env.DATABASE_URL || 'mongodb://localhost:3000/lefiatv2'
const store = new MongoDBStore({
url: dbUrl,
secret,
touchAfter: 24 * 60 * 60
});
store.on('error', function (e) {
console.log('session store error', e)
})
const sessionConfig = {
store,
name: 'session',
secret,
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: true,
expires: Date.now() + 1000 * 60 * 60 * 24 * 7,
maxAge: 1000 * 60 * 60 * 24 * 7
}
}
app.use(session(sessionConfig));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', indexRouter)
app.use('/trips', tripsRouter)
app.use('/gear', gearRouter)
app.use('/about', aboutRouter)
app.use('/blog', blogRouter)
app.use((err, req, res, next) => {
const { statusCode = 500 } = err;
if (!err.message) err.message = 'Oh No, Something Went Wrong!'
res.status(statusCode).render('error', { err })
})
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Serving on port ${port}`)
})
use optional chaining on your req.file.path so it would be like this
req.file?.path (kinda)
the error is telling you - hey where is the path?, there is no path in undefined - so your result if not passing the file will be
undefined.path
here is some example (i use nestjs):
async updateCommit(
#Res() res,
#Param('user_id') user_id: string,
#Param('repo_id') repo_id: string,
#Param('commited_id') commited_id: string,
#Body() updatedCommit: UpdateCommitDto,
#UploadedFile() file: UpdateCommitDto["file"]): Promise<User> {
Object.assign(updatedCommit, {
file: file?.path,
createdAt: false,
updatedAt: Date.now
})
const response = await this.commitService.updateCommit(user_id, repo_id, commited_id, updatedCommit)
return res.status(HttpStatus.OK).json({ response })}
The result :
Before update
After update
sorry for the image ( low reputation lol )
Related
POST requests return null. The req.body..... values are undefined. I tried to verify it arrives to the server in JSON format, but
i am not sure I am doing it in a right way.... :-(
Thanx a lot for help, amigos!
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const bodyParser = require('body-parser');
const cors = require("cors");
const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');
var app = express();
app.set('view engine', 'ejs')
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(bodyParser.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
const { MongoClient } = require("mongodb");
const uri = "mongod...the string is ok....y";
const client = new MongoClient(uri);
const database = client.db('holdocsDB');
const records = database.collection('records');
app.post("/users", async (req, res) => {
console.log('hola pooost');
console.log("req.body.age: " + req.body.age);
try {
// create a document to insert
const newRecord = {
firstName: req.body.firstName,
age: req.body.age
}
const result = await records.insertOne(newRecord);
console.log(`A document was inserted with the _id: ${result.insertedId}`);
// } finally {
// await client.close();
// }
} catch {
(e) => (console.error(e));
}
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.json('error');
});
module.exports = app;
When I hardcode some values to be posted in express POST route (instead of extracting the values from req.body) - it works well.
function RecordSearchBar() {
const [form, setForm] = useState({
firstName: "",
age: 0
});
// const navigate = useNavigate();
function updateForm(value) {
return setForm((prev) => {
return { ...prev, ...value };
});
}
async function onSubmit(e) {
e.preventDefault();
const newPerson = { ...form };
await fetch("http://localhost:3001/users/add", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newPerson),
})
.catch(error => {
window.alert(error);
return;
});
setForm({ firstName: "", age: ""});
// navigate("/users");
}
return (
<>
<h2>Search records:</h2>
<form onSubmit={onSubmit} id='search-form'>
<div className="form-group">
<label htmlFor="firstName">First name</label>
<input
type="text"
className="form-control"
id="name"
value={form.name}
onChange={(e) => updateForm({ name: e.target.value })}
/>
</div>
<div className="form-group">
<label htmlFor="age">Age</label>
<input
type="number"
className="form-control"
id="position"
value={form.position}
onChange={(e) => updateForm({ position: e.target.value })}
/>
</div>
<div className="form-group">
<input
type="submit"
value="Add record"
className="btn btn-primary"
/>
</div>
</form>
</>
Solved! I had to correct the type conversion of request body using JSON.parse() and JSON.stringify():
app.post("/users", async (req, res) => {
console.log("req.body: " + JSON.stringify(req.body));
let newRecordStringified = JSON.stringify(req.body)
try {
// create a document to insert
const newRecord = {
firstName: req.body.firstName,
age: req.body.age
// firstName: "Mamile",
// age: 33
}
const result = await records.insertOne(JSON.parse(newRecordStringified));
console.log(`A document was inserted with the _id: ${result.insertedId}`);
// } finally {
// await client.close();
// }
} catch {
(e) => (console.error(e));
}
})
Hello then i try to create new user i get error "message": "userdb validation failed: email: Path email is required."
cannot find there is a bad code field
controller.js
const { response } = require('express');
let Userdb = require('../model/model');
// create and save new user object
exports.create = (req, res) => {
// validate requast
if (!req.body) {
res.status(400).send({ message: 'Laukas negali būti tusčias!' });
return;
}
// new user
const user = new Userdb({
name: req.body.name,
email: req.body.email,
gender: req.body.gender,
status: req.body.status,
});
// save user to database
user
.save(user)
.then((data) => {
//res.send(data)
res.redirect('/add-user');
})
.catch((err) => {
res.status(500).send({
message: err.message || 'Kuriant kūrimo operaciją įvyko klaida',
});
});
};
// retrieve and ruturn all users
exports.find = (req, res) => {
Userdb.find();
if (req.query.id) {
const id = req.query.id;
Userdb.findById(id)
.then((data) => {
if (!data) {
res.status(404).send({ message: 'Nerastas naudotojas su id' + id });
} else {
res.send(data);
}
})
.catch((err) => {
res.status(500).send({ message: 'Error gaunant naudojo id' + id });
});
} else {
Userdb.find()
.then((user) => {
res.send(user);
})
.catch((err) => {
res
.status(500)
.send({
message:
err.message || 'Gaunant naudotojo informaciją įvyko klaida',
});
});
}
};
// update a new user by id
exports.update = (req, res) => {
if (!req.body) {
return res
.status(400)
.send({ message: 'Atnaujinant duomenis laukai negali būti tušti!' });
}
const id = req.params.id;
Userdb.findByIdAndUpdate(id, req.body, { useFindAndModify: false })
.then((data) => {
if (!data) {
res
.status(404)
.send({
message: `Negalima atnaujinti naudotojo su ${id}.Naudotojas nerastas!`,
});
} else {
res.send(data);
}
})
.catch((err) => {
res.status(500).send({ message: 'Error atnaujinti nepavyko' });
});
};
// Delete a user with user id
exports.delete = (req, res) => {
const id = req.params.id;
Userdb.findByIdAndDelete(id)
.then((data) => {
if (!data) {
res
.status(404)
.send({ message: `Negalima ištrinti su id ${id}. Blogas id` });
} else {
res.send({
message: 'Naudotojas ištrintas!',
});
}
})
.catch((err) => {
res.status(500).send({
message: 'Negalima ištrinti naudotojo su id=' + id,
});
});
};
model.js;
const mongoose = require('mongoose');
let schema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
gender: String,
status: String,
});
const Userdb = mongoose.model('userdb', schema);
module.exports = Userdb;
router.js;
const express = require('express');
const route = express.Router();
const services = require('../services/render');
const controller = require('../controller/controller');
/**
* #description Root Route
* #method GET/
*/
route.get('/', services.homeRoutes);
/**
* #description add users
* #method GET/ add-user
*/
route.get('/add-user', services.add_user);
/**
* #description for update user
* #method GET/ update-user
*/
route.get('/update-user', services.update_user);
// API
route.post('/api/users', controller.create);
route.get('/api/users', controller.find);
route.put('/api/users/:id', controller.update);
route.delete('/api/users/:id', controller.delete);
module.exports = route;
render.js;
const axios = require('axios');
exports.homeRoutes = (req, res) => {
// Make a get request to api users
axios
.get('http://localhost:3000/api/users')
.then(function (response) {
res.render('index', { users: response.data });
})
.catch((err) => {
res.send(err);
});
};
exports.add_user = (req, res) => {
res.render('add_user');
};
exports.update_user = (req, res) => {
res.render('update_user');
};
connection.js;
const mongoose = require('mongoose');
const connectDB = async () => {
try {
//mongoDB connection string
const con = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log(`MongoDB connected: ${con.connection.host}`);
} catch (err) {
console.log(err);
process.exit(1);
}
};
module.exports = connectDB;
server.js;
const express = require('express');
const dotenv = require('dotenv');
const morgan = require('morgan');
const bodyparser = require('body-parser');
const path = require('path');
const connectDB = require('./server/database/connection');
const app = express();
dotenv.config({ path: 'config.env' });
const PORT = process.env.PORT || 8080;
//log requests
app.use(morgan('tiny'));
// mongoDB connection
connectDB();
// parse request to body-parses
app.use(bodyparser.urlencoded({ extended: true }));
//set view engine
app.set('view engine', 'ejs');
//app.set("views",path.resolve(__dirname,"views/ejs"))
//load assets
app.use('/css', express.static(path.resolve(__dirname, 'assets/css')));
app.use('/img', express.static(path.resolve(__dirname, 'assets/img')));
app.use('/js', express.static(path.resolve(__dirname, 'assets/js')));
//css/style.css
//load routes
app.use('/', require('./server/routes/router'));
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
add this middleware app.use(bodyParser.json());
upper of app.use(bodyparser.urlencoded({extended:true}))
to get data from front
I am trying to create e registration for a new user with profile picture upload. But my form data is not passing to the route. I have added body-parser middleware but still, it seems something is wrong and I cannot find the reason.
Error:
D:\temp_project\smpms\routes\users.js:118
if (err) throw err;
^
Error: Illegal arguments: undefined, string
at _async (D:\temp_project\smpms\node_modules\bcryptjs\dist\bcrypt.js:214:46)
at Object.bcrypt.hash (D:\temp_project\smpms\node_modules\bcryptjs\dist\bcrypt.js:220:13)
at D:\temp_project\smpms\routes\users.js:117:28
at Immediate.<anonymous> (D:\temp_project\smpms\node_modules\bcryptjs\dist\bcrypt.js:153:21)
at processImmediate (internal/timers.js:456:21)
[nodemon] app crashed - waiting for file changes before starting...
app.js
const express = require("express");
const expressLayouts = require("express-ejs-layouts");
const mongoose = require("mongoose");
const passport = require("passport");
const flash = require("connect-flash");
const session = require("express-session");
const multer = require('multer');
const path = require('path');
var dotenv = require('dotenv').config();
const bodyParser = require('body-parser');
const app = express();
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.use(express.static("public"));
// Passport Config
require("./config/passport")(passport);
// DB Config
const db = require("./config/keys").mongoURI;
// Connect to MongoDB
mongoose
.connect(db, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log("MongoDB Connected"))
.catch((err) => console.log(err));
// EJS
app.use(expressLayouts);
app.set("view engine", "ejs");
// Express body parser
app.use(express.urlencoded({ extended: true }));
// Express session
app.use(
session({
secret: "secret",
resave: true,
saveUninitialized: true,
})
);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
// Connect flash
app.use(flash());
// Global variables
app.use(function (req, res, next) {
res.locals.success_msg = req.flash("success_msg");
res.locals.error_msg = req.flash("error_msg");
res.locals.error = req.flash("error");
next();
});
// Routes
app.use("/", require("./routes/index.js"));
app.use("/users", require("./routes/users.js"));
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server started on port ${PORT}`));
User.js - User model
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
avatar:{
type:String,
required:true
},
date: {
type: Date,
default: Date.now
}
});
const User = mongoose.model('User', UserSchema);
module.exports = User;
User.js route:
const express = require("express");
const router = express.Router();
const bcrypt = require("bcryptjs");
const passport = require("passport");
const multer = require('multer');
const path = require('path');
const bodyParser = require('body-parser')
const app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// Load User model
const User = require("../models/User");
const {forwardAuthenticated} = require("../config/auth");
// Login Page
router.get("/login", forwardAuthenticated, (req, res) => {
res.render("login", {title: "Login", layout: "layout"});
});
// Register Page
router.get("/register", forwardAuthenticated, (req, res) => {
res.render("register", {title: "Register", layout: "layout"});
});
// Register
router.post("/register", (req, res) => {
//const {name, email, password, password2||avatar} = req.body;
const name = req.body.name
const email = req.body.email
const password = req.body.password;
const password2 = req.body.password2;
const avatar = req.body.avatar;
let errors = [];
//
// if (!name || !email || !password || !password2) {
// errors.push({msg: "Please enter all fields"});
// }
// if (password && password.length < 6) {
// errors.push({msg: "Password must be at least 6 characters"});
// }
// if (password != password2) {
// errors.push({msg: "Passwords do not match"});
// }
if (errors.length > 0) {
res.render("register", {
errors,
name,
email,
password,
password2,
title: "Register",
layout: "Layout",
});
} else {
User.findOne({email: email}).then((user) => {
if (user) {
errors.push({msg: "Email already exists"});
res.render("register", {
errors,
name,
email,
password,
password2,
title: "Register",
layout: "Layout",
});
} else {
const newUser = new User({
name,
email,
password,
});
//Set The Storage Engine
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + newUser._id + path.extname(file.originalname));
}
});
// Init Upload
const upload = multer({
storage: storage,
limits: {fileSize: 1000000},
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
}
}).single('avatar');
// Check File Type
function checkFileType(file, cb) {
// Allowed ext
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb('Error: Images Only!');
}
}
console.log(newUser);
newUser.avatar = storage;
console.log(newUser);
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then((user) => {
req.flash(
"success_msg",
"You are now registered and can log in"
);
res.redirect("/users/login");
})
.catch((err) => console.log(err));
});
});
}
});
}
});
// Login
router.post("/login", (req, res, next) => {
passport.authenticate("local", {
successRedirect: "/dashboard",
failureRedirect: "/users/login",
failureFlash: true,
})(req, res, next);
});
// Logout
router.get("/logout", (req, res) => {
req.logout();
req.flash("success_msg", "You are logged out");
res.redirect("/users/login");
});
module.exports = router;
Register.ejs is the file where the form is not passing data to the route.
<div class="row mt-5">
<div class="col-md-6 m-auto">
<div class="card card-body">
<h1 class="text-center mb-3">
<i class="fas fa-user-plus"></i> Register
</h1>
<% include ./partials/messages %>
<%= typeof msg != 'undefined' ? msg : '' %>
<form action="/users/register" method="POST" enctype="multipart/form-data">
<div class="form-group">
<label for="name">Name</label>
<input
type="name"
id="name"
name="name"
class="form-control"
placeholder="Enter Name"
value="<%= typeof name != 'undefined' ? name : '' %>"
/>
</div>
<div class="form-group">
<label for="email">Email</label>
<input
type="email"
id="email"
name="email"
class="form-control"
placeholder="Enter Email"
value="<%= typeof email != 'undefined' ? email : '' %>"
/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
type="password"
id="password"
name="password"
class="form-control"
placeholder="Create Password"
value="<%= typeof password != 'undefined' ? password : '' %>"
/>
</div>
<div class="form-group">
<label for="password2">Confirm Password</label>
<input
type="password"
id="password2"
name="password2"
class="form-control"
placeholder="Confirm Password"
value="<%= typeof password2 != 'undefined' ? password2 : '' %>"
/>
</div>
<div class="form-group">
<label for="">Profile Picture</label>
<input type="file" name="avatar" id="" class="form-control file-path validate">
</div>
<button type="submit" class="btn btn-primary btn-block">
Register
</button>
</form>
<p class="lead mt-4">Have An Account? Login</p>
</div>
</div>
</div>
It seems that you aren't using multer correctly. Usually multer configuration is set globally and above all the APIs and then we pass that middleware function generated by multer to that specific API which has multipart/form-data header in its request. You have to move your configuration for multer, outside of your API, then pass the upload as a middleware to your API. Also from your clientside, you have to pass data properly. A good answer about sending JSON alongside the File with FormData object can be found here. Also you can add text fields in FormData object from clientside and receive it as object in req.body according to multer documentation. Just make sure you're passing data from clientside to server correctly. Here is your router with multer middleware:
const express = require("express");
const router = express.Router();
const fs = require('fs');
const bcrypt = require("bcryptjs");
const passport = require("passport");
const multer = require('multer');
const path = require('path');
const bodyParser = require('body-parser')
const app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// Load User model
const User = require("../models/User");
const { forwardAuthenticated } = require("../config/auth");
// Login Page
router.get("/login", forwardAuthenticated, (req, res) => {
res.render("login", { title: "Login", layout: "layout" });
});
// Register Page
router.get("/register", forwardAuthenticated, (req, res) => {
res.render("register", { title: "Register", layout: "layout" });
});
const storage = multer.diskStorage({
destination: './public/uploads/'
});
// Init Upload
const upload = multer({
storage: storage,
limits: { fileSize: 1000000 },
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
}
});
// Check File Type
function checkFileType(file, cb) {
// Allowed ext
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb('Error: Images Only!');
}
}
// Register
router.post("/register", upload.single('avatar'), (req, res) => {
//const {name, email, password, password2||avatar} = req.body;
const name = req.body.name
const email = req.body.email
const password = req.body.password;
const password2 = req.body.password2;
let errors = [];
//
// if (!name || !email || !password || !password2) {
// errors.push({msg: "Please enter all fields"});
// }
// if (password && password.length < 6) {
// errors.push({msg: "Password must be at least 6 characters"});
// }
// if (password != password2) {
// errors.push({msg: "Passwords do not match"});
// }
if (errors.length > 0) {
res.render("register", {
errors,
name,
email,
password,
password2,
title: "Register",
layout: "Layout",
});
} else {
User.findOne({ email: email }).then((user) => {
if (user) {
errors.push({ msg: "Email already exists" });
res.render("register", {
errors,
name,
email,
password,
password2,
title: "Register",
layout: "Layout",
});
} else {
const directory = "/images/";
const newUser = new User({
name,
email,
password,
avatar: `./public/uploads/${req.file}`
});
const filePath = path.join(__dirname, "../public/uploads/");
fs.rename(filePath + req.file.filename, req.file.fieldname + '-' + newUser._id + path.extname(req.file.originalname), (error) => {
if (error) {
return console.log(`Error: ${error}`);
}
});
newUser.avatar = 'public/uploads/' + req.file.fieldname + '-' + newUser._id + path.extname(req.file.originalname);
console.log(newUser);
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then((user) => {
req.flash(
"success_msg",
"You are now registered and can log in"
);
res.redirect("/users/login");
})
.catch((err) => console.log(err));
});
});
}
});
}
});
// Login
router.post("/login", (req, res, next) => {
passport.authenticate("local", {
successRedirect: "/dashboard",
failureRedirect: "/users/login",
failureFlash: true,
})(req, res, next);
});
// Logout
router.get("/logout", (req, res) => {
req.logout();
req.flash("success_msg", "You are logged out");
res.redirect("/users/login");
});
module.exports = router;
It will save your file without any problem (if your configuration about directory and filename was okay).
i'm fairly new to express js i want to do a login app so far i did the register part but in login app i want to do the comparaison between the password in database and the password provided by the user and compare it with bcrypt since i'm using it to crypt password , but its not doing the comparaison , what i'm missing here
router
const express = require('express')
const router = express.Router()
const bcrypt = require('bcrypt');
const User = require('../models/user')
const jwt = require('jsonwebtoken')
router.get('/login', function (req, res) {
res.render('login')
})
router.get('/', function (req, res) {
res.render('home')
})
router.get('/register', function (req, res) {
res.render('register')
})
router.post('/register', async function(req,res){
User.beforeCreate((user, options) => {
return bcrypt.hash(user.password, 10)
.then(hash => {
user.password = hash;
})
.catch(err => {
throw new Error();
});
});
return User.create({
username: req.body.name,
password: req.body.password,
email: req.body.email,
createdAt: Date.now()
}).then(function (users) {
res.send(users);
}).catch((err)=>{
console.log(err)
})
})
router.post('/login', function(req,res){
User.findOne({
where:{
username:req.body.name
}
})
.then(user=>{
if(user){
if(bcrypt.compareSync(req.body.password,user.password)){
let token = jwt.sign(user.dataValues,secretKey,{
expiresIn:1440
})
res.send(token)
}
else {
res.status(400).json({
error:'error exissts'
})
}
}
})
.catch(err=>{
res.status(400).json({err:err})
})
})
module.exports = router
models
const sequelize = require('../database/db.js')
const Sequelize = require('sequelize');
const User = sequelize.define('authentication',{
username: {
type: Sequelize.STRING,
allowNull: false
},
password: {
type: Sequelize.STRING
// allowNull defaults to true
} ,
email: {
type: Sequelize.STRING
// allowNull defaults to true
},
created_at: {
field: 'createdAt',
type: Sequelize.DATE,
},
updated_at: {
field: 'updatedAt',
type: Sequelize.DATE,
},
}, {
freezeTableName: true
},
{
notNull: { args: true, msg: "You must enter a name" }
},
)
module.exports = User
index
const express = require('express');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const path = require('path');
// const passport = require('passport');
// const passportJWT = require('passport-jwt');
// Database
const db = require('./database/db');
// Test DB
db.authenticate()
.then(() => console.log('Database connected...'))
.catch(err => console.log('Error: ' + err))
const app = express();
// Handlebars
app.engine('handlebars', exphbs({ defaultLayout: 'main' }));
app.set('view engine', 'handlebars');
// Body Parser
app.use(bodyParser.urlencoded({ extended: false }));
// Set static folder
app.use(express.static(path.join(__dirname, 'public')));
// Importing files
const routes = require("./routes/route");
app.use("/", routes);
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server started on port ${PORT}`));
index.js
const express = require('express');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const path = require('path');
// const passport = require('passport');
// const passportJWT = require('passport-jwt');
// Database
const db = require('./database/db');
// Test DB
db.authenticate()
.then(() => console.log('Database connected...'))
.catch(err => console.log('Error: ' + err))
const app = express();
// Handlebars
app.engine('handlebars', exphbs({ defaultLayout: 'main' }));
app.set('view engine', 'handlebars');
// Body Parser
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
// Set static folder
app.use(express.static(path.join(__dirname, 'public')));
// Importing files
const routes = require("./routes/route");
app.use("/", routes);
const PORT = process.env.PORT || 4500;
app.listen(PORT, console.log(`Server started on port ${PORT}`));
route.js
const express = require('express')
const router = express.Router()
const bcrypt = require('bcrypt');
const User = require('../models/user')
const jwt = require('jsonwebtoken')
const uuid = require('uuidv4').default;
const secretKey = '321'
router.get('/login', function (req, res) {
res.render('login')
})
router.get('/', function (req, res) {
res.render('home')
})
router.get('/register', function (req, res) {
res.render('register')
})
router.post('/register', function(req,res){
User.beforeCreate((user, options) => {
return bcrypt.hash(user.password, 10)
.then(hash => {
user.password = hash;
})
.catch(err => {
throw new Error();
});
});
return User.create({
id: uuid(),
username: req.body.name,
password: req.body.password,
email: req.body.email,
createdAt: Date.now()
}).then(function (users) {
res.send(users);
}).catch((err)=>{
console.log(err)
})
})
router.post('/login', function(req,res){
User.findOne({
where:{
username:req.body.name
}
})
.then(user=>{
if(user){
if(bcrypt.compareSync(req.body.password,user.password)){
let token = jwt.sign(user.dataValues,secretKey,{
expiresIn:1440
})
res.send(token)
}
else {
res.status(400).json({
error:'error exissts'
})
}
}
})
.catch(err=>{
res.status(400).json({err:err})
})
})
module.exports = router
just add app.use(bodyParser.json()) in index.js and define secretKey also add id in user model for primary key and the code working properly
So I am making this website where you can see different recipes for food. When browsing for recipes, I want the user to be able to select a category and browse all the dishes that fall under it (i.e dessert, dinner, vegan etc).
I have this function I created in my router file that returns all the dishes that fall under the specified category:
router.get('/showrecipes/:categoryname', (req, res, next) => {
let nameQuery = {category: req.params.categoryname};
Recipe.find(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
});
});
However, when I try to test it out in Postman, I keep getting Null instead of all the dishes that fall under the category.
All my other functions are correctly working, but this one seems to have issues.
For reference, here is the rest of the recipeRouter file:
const express = require('express');
const passport = require('passport');
const Recipe = require('../models/recipe');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
router = express.Router();
router.get('/', (req, res, next) => {
res.json('Here are the recipes!')
});
// Is working
router.get('/showrecipes', (req, res, next) => {
Recipe.find({}, (err, recipes) => {
if (err) throw err;
res.json(recipes);
});
});
// Is working.
router.get("/showrecipes/:recipename", (req, res, next) => {
let nameQuery = {name: req.params.recipename};
Recipe.findOne(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
})
});
// Is not crashing, but is returning Null which isn't how it's supposed to work.
router.get('/showrecipes/:categoryname', (req, res, next) => {
let nameQuery = {category: req.params.categoryname};
Recipe.find(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
});
});
// Now it's working, good stuff.
router.post('/addrecipe', (req, res, next) => {
Recipe.create({
name: req.body.name,
description: req.body.description,
steps: req.body.steps,
ingredients: req.body.ingredients,
category: req.body.category,
}, (err, recipe) => {
if (err) throw err;
// Recipe.save();
res.json(recipe);
});
});
// See if this works
router.put('editrecipe/:recipename/:editedField', (req, res, next) => {
Recipe.findOneAndUpdate({name: req.params.recipename}, {$set: req.body}, {new: true}, (err, recipe) => {
if (err) throw err;
res.json(recipe)
});
});
// It's working, thank god
router.delete('/deleterecipe/:recipename', (req, res, next) => {
let nameQuery = {name: req.params.recipename};
Recipe.findOneAndRemove(nameQuery, (err, recipe) => {
if (err) throw err;
res.send('Dish was succesfully deleted!')
});
});
module.exports = router;
And here is my app.js file
let express = require('express');
let mongoose = require('mongoose');
let path = require('path');
let bodyParser = require('body-parser');
let recipeRouter = require('./routes/recipeRouter');
let userRouter = require('./routes/userRouter');
let bcrypt = require('bcrypt');
let passport = require('passport');
let LocalStrategy = require('passport-local').Strategy;
let config = require('./config');
mongoose.connect(config.mongoUrl);
let db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
// we're connected!
console.log("Connected correctly to server");
});
const app = express();
const port = 3000;
app.listen(port);
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.set('views', path.join(__dirname, 'views'));
app.use('/users', userRouter);
app.use('/recipes',recipeRouter);
app.get('/', function(req, res){
res.send('Hey, this is your database!')
});
module.exports = app;
And here is my Recipe file
const express = require('express');
const mongoose = require('mongoose');
const User = require('../models/user');
let Schema = mongoose.Schema;
let commentSchema = Schema({
rating: {
type: Number,
required: true,
min: 1,
max: 5,
},
comment: {
type: String,
required: true
},
postedBy: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
let Comment = mongoose.model('Comment', commentSchema);
let recipeSchema = Schema({
name: {
type: String,
required: true
},
description: {
type: String,
},
steps: {
type: String,
required: true,
},
ingredients: {
type: Array,
required: true
},
comments: [commentSchema],
category: {
type: String,
required: true,
},
postedBy: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
/// So I learnt that by defining the string as "Recipe" in the model function, I will have to lower case it
/// and pluralize it when I use it with res.json and other such things (i.e. "Recipe" => recipes).
let Recipe = mongoose.model('Recipe', recipeSchema);
module.exports = Recipe;
/// refactor this so that these are in the router, not in the models file
/*
module.exports.getRecipeByName = (name, callback) => {
let nameQuery = {name: name};
Recipe.findOne(nameQuery, callback);
};
module.exports.getRecipesByCategory = (category, callback) => {
Recipe.find({'category': category});
};
*/