Related
In my Express backend, I have set up a connection with S3 Bucket for uploading images, and it works.
However additionally, I would like to be able to store a reference link (S3 url) of the saved image in my Mongo Database.
I have been trying to play around with req.file object but somehow, I cannot get the req.file.location, whereas req.file.buffer works okay (as in the example below in itemController.js). Is there any problem in my s3.js configuration? Or pehraps I would need a different approach to get req.file.location instead of buffer?
Below my bucket configuration s3.js
// s3.js
const AWS = require('aws-sdk')
// s3 bucket configuration
const awsConfig = {
accessKeyid : process.env.S3_ACCESS_KEY,
secretAccessKey : process.env.S3_ACCESS_SECRET,
region : process.env.S3_REGION
}
const S3 = new AWS.S3(awsConfig)
//s3 bucket upload function
const uploadToS3 = (fileData) => {
return new Promise ((resolve, reject) =>{
const params = {
Bucket : process.env.S3_BUCKET_NAME,
Key: `${Date.now().toString()}.jpg`,
Body: fileData
}
S3.upload(params, (err, data) =>{
if(err){
console.log(err)
reject(err)
}
console.log(data)
return resolve(data)
})
})
}
module.exports = {
uploadToS3
}
Here is my itemController.js
const Item = require('../models/itemModel')
const Worker = require('../models/workerModel')
const mongoose = require('mongoose')
const multer = require('multer')
const { uploadToS3 } = require('../s3')
//! Multer configuration
const multerConfig = {
limits: 1024 * 1024 * 5,
fileFilter: function (req, file, done) {
if (file.mimetype === "image/jpg"|| file.mimetype === "image/png" || file.mimetype ==='image/jpeg') {
done(null, true)
} else {
done("Niewłaściwy plik, użyj .jpg .jpeg .png", false)
}
}
}
const upload = multer(multerConfig)
//! CREATE new item
const createItem = async (req, res) => {
// multer middleware that handles file upload
upload.single("image")(req, res, async () => {
//destructuring form req.body
const {
title,
model,
producer,
serialNumber,
yearOfProduction,
atEmployee,
seller,
warrantyDate,
purchaseDate,
image,
} = req.body
if (!title){
return res.status(400).json({error:'Błąd! Wymagane jest podanie chociaż nazwy narzędzia.'})
}
//try-catch to create new Item and catch error. Add "await" because of "async" - Js promise above
try {
const item = await Item.create({
title,
model,
producer,
serialNumber,
yearOfProduction,
atEmployee,
seller,
warrantyDate,
purchaseDate,
image: req.file ? req.file.buffer : image,
})
if (req.file) {
// upload file to S3 and store the URL in the database
const result = await uploadToS3(req.file.buffer)
item.imageUrl = result.location
await item.save()
}
res.status(200).json(item)
} catch(error) {
res.status(400).json({error: error.message})
}
})
}
...
And here is my ItemModel.js
const mongoose = require('mongoose')
//mongoose function to create new model Schema
const Schema = mongoose.Schema
const itemSchema = new Schema ({
title: {
type: String,
required: true,
},
producer: {
type: String,
required: false,
},
model: {
type: String,
required: false,
},
serialNumber: {
type: String,
required: false,
},
yearOfProduction:{
type: Number,
required: false
},
seller:{
type: String,
required: false
},
purchaseDate: {
type: Date,
default: Date.now
},
warrantyDate: {
type: Date,
required: false,
},
//Linking Worker model to an Item
atEmployee: {
type: mongoose.Schema.Types.ObjectId,
required: false,
ref:'Worker',
},
image: {
type: String,
required: false,
}
}, { timestamps: true })
module.exports = mongoose.model('Item', itemSchema)
This is how I actually solved it
itemController.js
const Item = require('../models/itemModel')
const Worker = require('../models/workerModel')
const mongoose = require('mongoose')
const multer = require('multer')
const { uploadToS3 } = require('../s3')
//! Multer configuration
const multerConfig = {
limits: 1024 * 1024 * 5,
fileFilter: function (req, file, done) {
if (file.mimetype === "image/jpg"|| file.mimetype === "image/png" || file.mimetype ==='image/jpeg') {
done(null, true)
} else {
done("Niewłaściwy plik, użyj .jpg .jpeg .png", false)
}
}
}
const upload = multer(multerConfig)
//! CREATE new item
const createItem = async (req, res) => {
// multer middleware that handles file upload
upload.single("image")(req, res, async () => {
//destructuring form req.body
const {
title,
model,
producer,
serialNumber,
yearOfProduction,
atEmployee,
seller,
warrantyDate,
purchaseDate,
image,
} = req.body
if (!title){
return res.status(400).json({error:'Błąd! Wymagane jest podanie chociaż nazwy narzędzia.'})
}
//try-catch to create new Item and catch error. Add "await" because of "async" - Js promise above
try {
let item = {}
if (req.file) {
// upload file to S3 and store the URL in the database if image has been uploaded
const result = await uploadToS3(req.file.buffer)
item = await Item.create({
title,
model,
producer,
serialNumber,
yearOfProduction,
atEmployee,
seller,
warrantyDate,
purchaseDate,
image: result.Location,
})
//if no image, show nothing
} else {
item = await Item.create({
title,
model,
producer,
serialNumber,
yearOfProduction,
atEmployee,
seller,
warrantyDate,
purchaseDate,
})
}
res.status(200).json(item)
} catch(error) {
res.status(400).json({error: error.message})
}
})
}
I am trying to send data from front end to back end with react and nodejs. but when I console in front end it appear data but in backend it didn't get anything.
Here is my front end code:
const [imageSelected, setImageSelected] = useState("");
// Form submission
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append("file", imageSelected);
const payload = { title, mission, isSearchable, userId: currentUser.id };
formData.append("payload", payload);
// Send post request for signup
const res = await axios.post("/api/v1/teams/team", formData, {
headers: { "Content-type": "multipart/form-data" },
});
// If no validation errors were found
if (res.data.validationErrors === undefined) {
// Clear any errors
setErrorsArr([]);
// Hide the errors component
setShowErrors(false);
// Toggle the modal
toggleModal();
// Go to team management page
NextRouter.push(`/team/${res.data}`);
} else {
// Set errors
setErrorsArr(res.data.validationErrors.errors);
// Show the errors component
setShowErrors(true);
}
};
<input
type="file"
className="team--modal_upload_avatar"
ref={inputFile}
onChange={(e) => setImageSelected(e.target.files[0])}
/>
<Grid item xs={12} className={classes.avatarDiv}>
<Avatar
aria-label="team"
className={classes.avatar}
component="div"
onClick={onButtonClick}
>
<AddAPhotoIcon className={classes.avatarIcon} />
</Avatar>
Here is my route:
const express = require("express");
const router = express.Router();
const { catchErrors } = require("../errors/errorHandlers");
const { body, param } = require("express-validator");
const cloudinary = require("cloudinary").v2;
const path = require("path");
const Datauri = require("datauri/parser");
const cloud_name = process.env.CLOUDINARY_NAME;
const cloud_api_key = process.env.CLOUDINARY_API_KEY;
const cloud_api_secret = process.env.CLOUDINARY_API_SECRET;
const cloud_url = process.env.CLOUDINARY_URL;
cloudinary.config({
cloud_name: cloud_name,
api_key: cloud_api_key,
api_secret: cloud_api_secret,
cloudinary_url: cloud_url,
});
// Controller
const {
createTeam,
getUsersTeams,
getManagedTeams,
getTeamCredits,
getTeamData,
updateTeamData,
shutdownTeam,
checkTeamPermissions,
checkTeamPermissionsAndLimits,
addMember,
removeMember,
addMemberBackToTeam,
quitTeam,
} = require("./teamsController");
const {
checkUserVerification,
restrictedRoute,
checkData,
} = require("../helpers/apiHelpers");
router.post(
"/team",
(req, res) => {
console.log(res);
console.log("req body", req.body);
console.log("req files", req.files);
console.log("req user", req.user);
const dUri = new Datauri();
const dataUri = (req) =>
dUri.format(path.extname(req.name).toString(), req.data);
if (req.files !== undefined && req.files !== null) {
const { file, id } = req.files;
const newFile = dataUri(file).content;
cloudinary.uploader
.upload(newFile, {
folder: "TeamAvatar",
})
.then((result) => {
const imageUrl = result.url;
const data = { id: req.body.id, imageUrl };
createTeam(data);
return res
.status(200)
.json({ message: "Success", data: { imageUrl } });
})
.catch((err) =>
res.status(400).json({ message: "Error", data: { err } })
);
} else {
return res.status(400).json({ message: "Error" });
}
},
restrictedRoute,
[
body(
"title",
"Only alphabetical characters, numbers, and spaces are allowed."
)
.not()
.isEmpty()
.isLength({ min: 1, max: 25 })
.trim()
.matches(/^[a-zA-Z0-9 ]+$/)
.blacklist("\\<\\>\\;\\[\\]\\{\\}\\|\\%\\=\\(\\)\\~\\#")
.escape(),
body("mission", "Only alphabetical characters and spaces are allowed.")
.not()
.isEmpty()
.trim()
.blacklist("\\<\\>\\;\\[\\]\\{\\}\\|\\%\\=\\(\\)\\~\\#")
.escape(),
],
checkData,
catchErrors(checkUserVerification),
catchErrors(createTeam)
);
Here is my controller that have create team function:
exports.createTeam = async (req, res) => {
// Get the user id from the session
const userId = req.session.passport.user.id;
console.log("body", req.body);
console.log("files", req.files);
console.log("file", req.file);
// Make sure user has the credits to create a new team
const teamInfo = await models.User.findOne({
where: {
id: userId,
},
attributes: ["teamCredits"],
});
if (teamInfo.dataValues.teamCredits <= 0) {
res.status(200).json({
validationErrors: {
errors: [
{
msg: "You don't have any more team credits.",
},
],
},
});
return;
}
const { title, mission } = req.body;
// const { picture } = req.imageUrl;
// Make sure the user hasn't already created a team with that title.
const existingTeam = await models.Team.findOne({
where: {
title: title,
creatorId: userId,
},
});
if (existingTeam !== null) {
// Response and let the user know.
res.status(200).json({
validationErrors: {
errors: [
{
msg: "You already created a team with that name.",
},
],
},
});
return;
}
// Generator a public team id
const firstLetter = title[0];
const secondLetter = title[1];
const thirdLetter = title[2];
const timePart = Date.now();
const generatedPublicId = `${firstLetter}${secondLetter}${thirdLetter}${timePart}`;
const roomEntry = {
name: title,
status: true,
};
const roomResponse = await models.Room.create({ ...roomEntry });
const defaultTeamValues = {
title: title,
type: "simple team",
mission: mission,
// picture: picture,
agreement: "default",
inputs: "",
outputs: "",
duration_in_months: 12,
status: "Seeking new members",
public_team_id: generatedPublicId,
mergedTo: null,
creatorId: userId,
date_closed: null,
current_members_count: 1,
current_invites_count: 0,
max_team_members_allowed: 10,
max_invites_allowed: 20,
roomID: roomResponse.dataValues.id,
};
// No existing team was found with that title and created by that user.
// Create team.
const team = await models.Team.create(defaultTeamValues);
const defaultRoleValues = {
title: "creator",
duties: "",
rights: "all",
};
// Create role for new team
const role = await models.Role.create(defaultRoleValues);
const defaultMembershipValues = {
interests: "",
contributions: "",
authorization: "creator",
status: "active",
application_letter: "",
date_applied: Sequelize.literal("CURRENT_TIMESTAMP"),
date_joined: Sequelize.literal("CURRENT_TIMESTAMP"),
date_departed: null,
memberId: userId,
teamId: team.dataValues.id,
roleId: role.dataValues.id,
};
// Create membership for team with role and team ids
await models.Membership.create(defaultMembershipValues);
const newCreditValue = teamInfo.dataValues.teamCredits - 1;
// Update team credits the user has.
await models.User.update(
{ teamCredits: newCreditValue },
{
where: {
id: userId,
},
}
);
// Done
res.status(200).json(team.dataValues.public_team_id);
};
Why my back end didn't get any data I sent from front end to back end?
Add files
server.js:
/* eslint-disable no-undef */
const express = require("express");
const next = require("next");
const dotenv = require("dotenv");
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
const compression = require("compression");
const bodyParser = require("body-parser");
const logger = require("morgan");
const session = require("express-session");
const SequelizeStore = require("connect-session-sequelize")(session.Store);
const passport = require("passport");
const helmet = require("helmet");
const sslRedirect = require("heroku-ssl-redirect");
const socketIo = require("socket.io");
const http = require("http");
const {
saveMessage,
getAllMessagedByRoomID,
} = require("./services/chat/chatController");
// Setup Next.js then run express.
app.prepare().then(() => {
// Setup express
const server = express();
const chatServer = http.createServer(server);
const io = socketIo(chatServer);
// Socket Connection Start
io.on("connection", (socket) => {
chatID = socket.handshake.query.chatID;
socket.join(chatID);
//Send message to only a particular user
socket.on("send_message", (message) => {
saveMessage(message);
io.in(message.roomID).emit("receive_message", {
content: message.content,
roomID: message.roomID,
userID: message.userID,
});
});
socket.on("get_all_messages", async ({ roomID }) => {
const allMessagedByRoomID = await getAllMessagedByRoomID(roomID);
io.in(roomID).emit("send_all_messages", {
allMessagedByRoomID,
});
});
});
// Redirect all traffic to use ssl(https);
server.use(sslRedirect());
// Define PORT
const port = process.env.PORT || 3000;
let serverMode = "development";
// Check if node is setup for production
if (!dev) {
serverMode = "production";
}
if (serverMode === "production") {
server.use(helmet());
}
// Logger
server.use(
logger("dev", {
skip: function (req, res) {
return res.statusCode < 199; // Only log 400 and 500 codes
},
})
);
// Use body parser
server.use(bodyParser.urlencoded({ extended: false }));
server.use(bodyParser.json());
// Compression
server.use(compression());
// Database
const db = require("./models/index");
const sequelize = db.sequelize;
// Test db connection
sequelize
.authenticate()
.then(() => {
console.log("Database successfully connected!");
})
.catch((err) => {
throw new Error(err);
});
// Sessions Setup
const sessionMaxTime = 1000 * 60 * 60 * 24 * 5; // 5 Days
// Session options
const theSession = {
secret: process.env.SECRET,
name: "sessId",
resave: false,
saveUninitialized: false,
cookie: {
maxAge: sessionMaxTime,
sameSite: true,
},
store: new SequelizeStore({
db: sequelize,
table: "Session",
}),
};
// Session production options
if (serverMode === "production") {
server.set("trust proxy", 1); // Trust first proxy
theSession.cookie.secure = true; // Serve cookies on HTTPS only
}
server.use(session(theSession));
// Passport Setup
// require("./config/passport")(passport);
require("./config/passport");
server.use(passport.initialize());
server.use(passport.session());
// API Routes
const userRoutes = require("./services/users/usersAPI");
server.use("/api/v1/users", userRoutes);
const profileRoutes = require("./services/profiles/profilesAPI");
server.use("/api/v1/profiles", profileRoutes);
const teamRoutes = require("./services/teams/teamsAPI");
server.use("/api/v1/teams", teamRoutes);
const searchRoutes = require("./services/searches/searchAPI");
server.use("/api/v1/search", searchRoutes);
const ratingRoutes = require("./services/ratings/ratingsAPI");
server.use("/api/v1/ratings", ratingRoutes);
const inviteRoutes = require("./services/invites/invitesAPI");
server.use("/api/v1/invites", inviteRoutes);
const feedbackRoutes = require("./services/feedback/feedbackAPI");
server.use("/api/v1/feedback", feedbackRoutes);
const couponRoutes = require("./services/coupons/couponsAPI");
server.use("/api/v1/coupons", couponRoutes);
const chatRoutes = require("./services/chat/chatAPI");
server.use("/api/v1/chat", chatRoutes);
// Restricted Pages
const restrictedRoutes = require("./services/restricted/restrictedAPI");
server.use(restrictedRoutes);
// Run server
sequelize.sync({ force: true }).then(() => {
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready in ${serverMode} mode.`);
});
});
});
To handle HTTP POST requests in Express.js version 4 and above, you need to install the middleware module called body-parser.
body-parser extracts the entire body portion of an incoming request stream and exposes it on req.body.
const express = require('express')
const app = express()
const bodyParser = require('body-parser');
// support parsing of application/json type post data
app.use(bodyParser.json());
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true }));
router.post("/team", (req, res) => {...})
In Addition:
To handle multipart/form-data request that support file upload, you
need to use multer multer module.
Basic usage example:
Don't forget the enctype="multipart/form-data" in your form.
<form action="/profile" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body will contain the text fields, if there were any
})
In your case: route.js
const express = require("express");
const app = express();
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const router = express.Router();
const { catchErrors } = require("../errors/errorHandlers");
const { body, param } = require("express-validator");
const cloudinary = require("cloudinary").v2;
const path = require("path");
const Datauri = require("datauri/parser");
const cloud_name = process.env.CLOUDINARY_NAME;
const cloud_api_key = process.env.CLOUDINARY_API_KEY;
const cloud_api_secret = process.env.CLOUDINARY_API_SECRET;
const cloud_url = process.env.CLOUDINARY_URL;
cloudinary.config({
cloud_name: cloud_name,
api_key: cloud_api_key,
api_secret: cloud_api_secret,
cloudinary_url: cloud_url,
});
// Controller
const {
createTeam,
getUsersTeams,
getManagedTeams,
getTeamCredits,
getTeamData,
updateTeamData,
shutdownTeam,
checkTeamPermissions,
checkTeamPermissionsAndLimits,
addMember,
removeMember,
addMemberBackToTeam,
quitTeam,
} = require("./teamsController");
const {
checkUserVerification,
restrictedRoute,
checkData,
} = require("../helpers/apiHelpers");
router.post(
"/team", upload.single('file'),
(req, res) => {
console.log(res);
// req.file is the `file` file
// req.body will hold the text fields, if there were any
console.log("req body", req.body);
console.log("req file", req.file);
console.log("req user", req.user);
const dUri = new Datauri();
const dataUri = (req) =>
dUri.format(path.extname(req.name).toString(), req.data);
if (req.files !== undefined && req.files !== null) {
const { file, id } = req.files;
const newFile = dataUri(file).content;
cloudinary.uploader
.upload(newFile, {
folder: "TeamAvatar",
})
.then((result) => {
const imageUrl = result.url;
const data = { id: req.body.id, imageUrl };
createTeam(data);
return res
.status(200)
.json({ message: "Success", data: { imageUrl } });
})
.catch((err) =>
res.status(400).json({ message: "Error", data: { err } })
);
} else {
return res.status(400).json({ message: "Error" });
}
},
restrictedRoute,
[
body(
"title",
"Only alphabetical characters, numbers, and spaces are allowed."
)
.not()
.isEmpty()
.isLength({ min: 1, max: 25 })
.trim()
.matches(/^[a-zA-Z0-9 ]+$/)
.blacklist("\\<\\>\\;\\[\\]\\{\\}\\|\\%\\=\\(\\)\\~\\#")
.escape(),
body("mission", "Only alphabetical characters and spaces are allowed.")
.not()
.isEmpty()
.trim()
.blacklist("\\<\\>\\;\\[\\]\\{\\}\\|\\%\\=\\(\\)\\~\\#")
.escape(),
],
checkData,
catchErrors(checkUserVerification),
catchErrors(createTeam)
);
I am trying to upload images in mongo db but after clicking on send in postman it shows "img": null
I am using flutter for frontend so I want to make a rest api I am able to upload single image but when I am trying to upload multiple images it shows
"img": null
I have also created a schema
where I have set
img:{
type: array,
default:"",
}
const express = require("express");
const router = express.Router();
const Profile = require("../models/profile.model");
const middleware = require("../middleware");
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./uploads");
},
filename: (req, file, cb) => {
cb(null, req.decoded.username + ".jpg");
},
});
const fileFilter = (req, file, cb) => {
if (file.mimetype == "image/jpeg" || file.mimetype == "image/png") {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 6,
},
// fileFilter: fileFilter,
});
//adding and update profile image
router
.route("/add/image")
.patch(middleware.checkToken, upload.array("img",5), (req, res) => {
Profile.findOneAndUpdate(
{ username: req.decoded.username },
{
$set: {
img: req.files.path,
},
},
{ new: true },
(err, profile) => {
if (err) return res.status(500).send(err);
const response = {
message: "image added successfully updated",
data: profile,
};
return res.status(200).send(response);
}
);
});
when you upload multiple images, multer create a array of object like this :
req.files : [{…}, {…}, {…}]
that one of the property of objects is path, so there are many way to insert to path in img.
if type of img defined array [] in schema you can do like this in findOneAndUpdate :
{
$set: {
img: req.files.map(file => file.path),
},
}
I am trying to upload multiple images with Nodejs, Expressjs and Multer-s3, but it's not working.
I have a model called Program and the Program model has an array image attribute but when I try to upload multiple images my req.file returns undefined.
Here is my model
const programSchema = new mongoose.Schema({
programtype: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
createdAt: {
type: Date,
required: true,
default: Date.now,
},
programImage: {
type: Array,
require: true,
},
});
and my routes
const Program = require("../models/program");
const fs = require("fs");
const multer = require("multer");
const path = require("path");
var AWS = require("aws-sdk");
var multerS3 = require("multer-s3");
AWS.config.update({
secretAccessKey: process.env.S3_SECRECT,
accessKeyId: process.env.AWS_ACCESS_KEY,
region: process.env.S3_REGION,
});
const uploadPath = path.join("public", Program.programImageBasePath);
const imageMineTypes = ["image/jpeg", "image/png", "image/gif"];
const bucketname = "mybucketname";
s3 = new AWS.S3();
const upload = multer({
storage: multerS3({
s3: s3,
acl: "public-read",
bucket: bucketname,
s3BucketEndpoint: true,
endpoint: "http://" + bucketname + ".s3.amazonaws.com",
key: function (req, file, cb) {
const uploadPathWithOriginalName = uploadPath + "/" + file.originalname;
cb(null, uploadPathWithOriginalName);
},
}),
});
router.post("/create", upload.array("cover", 10), async (req, res, next) => {
console.log(req.file);
const program = new Program({
programtype: req.body.programtype,
title: req.body.title,
description: req.body.description,
programImage: req.file.location,
});
try {
const programs = await program.save();
res.redirect("/programs");
} catch {
if (program.programImage != null) {
removeprogramImage(program.programImage);
}
res.render("programs/new");
}
});
and my views
<h2 style="padding-top: 90px;" > New Programs</h2>
<form action="/programs/create" method="POST" enctype="multipart/form-data">
<div>
<label>Image</label>
<input type="file" name="cover" multiple />
</div>
Cacel
<button type="submit">Create</button>
</form>
You can refer to this example.
const s3 = new AWS.S3({
accessKeyId: 'xxxxxxxxx',
secretAccessKey: 'xxxxxxxxx'
});
const uploadS3 = multer({
storage: multerS3({
s3: s3,
acl: 'public-read',
bucket: 'xxxxxxxx',
metadata: (req, file, callBack) => {
callBack(null, { fieldName: file.fieldname })
},
key: (req, file, callBack) => {
var fullPath = 'products/' + file.originalname;//If you want to save into a folder concat de name of the folder to the path
callBack(null, fullPath)
}
}),
limits: { fileSize: 2000000 }, // In bytes: 2000000 bytes = 2 MB
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
}
}).array('photos', 10);
exports.uploadProductsImages = async (req, res) => {
uploadS3(req, res, (error) => {
console.log('files', req.files);
if (error) {
console.log('errors', error);
res.status(500).json({
status: 'fail',
error: error
});
} else {
// If File not found
if (req.files === undefined) {
console.log('uploadProductsImages Error: No File Selected!');
res.status(500).json({
status: 'fail',
message: 'Error: No File Selected'
});
} else {
// If Success
let fileArray = req.files,
fileLocation;
const images = [];
for (let i = 0; i < fileArray.length; i++) {
fileLocation = fileArray[i].location;
console.log('filenm', fileLocation);
images.push(fileLocation)
}
// Save the file name into database
return res.status(200).json({
status: 'ok',
filesArray: fileArray,
locationArray: images
});
}
}
})
};
I am using expo-image-picker in react-native to pick image/video files and multer in nodejs as middleware to download files in directory /public/upload. When i am uploading file along with other parameters from react-native, multer is unable to detect a file present in req.body and hence not downloading any file.
Here is my react-native code using axios
pickImage = async () => {
try {
let options = {
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 1,
// base64:true
}
let result = await ImagePicker.launchImageLibraryAsync(options)
if (!result.cancelled) {
this.setState({ content: result })
}
} catch (E) {
console.log("error in picking image:", E)
}
}
createFormData = (response) => {
const photo = {
uri: response.uri,
type: response.type,
name: "my-img.jpg",
};
const form = new FormData();
form.append('acivityFile',photo);
return form;
};
handleSubmit = async () => {
if (this.state.content) {
const formData = this.createFormData(this.state.content)
console.log("form data:", formData)
try {
const res = await axios.post('http://393ad751391b.ngrok.io/activities',
{
title: "This is the title",
description: "This is a description",
eventType: "LOST & FOUND",
file: formData
},
{
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
},
)
console.log("res:", res.data);
} catch (err) {
console.log("err in post axios:",err)
}
}
}
Here is my route file handling http requests in server-side
const express = require('express');
const Upload = require('./../utils/multerSetup');
const activityController = require('../Controllers/activityController');
const router = express.Router();
router
.route('/')
.get(activityController.getAllActivities)
.post(
Upload.single('activityFile'),
activityController.addActivity
);
Here is my multerSetup.js file in server-side
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/');
},
filename: function (req, file, cb) {
const ext = file.mimetype.split('/')[1];
cb(null, file.fieldname + '-' + Date.now() + '.' + ext);
},
});
const upload = multer({ storage });
module.exports = upload;
Here is my activityController.js file in server-side
const Activity = require('./../modals/activityModel');
const User = require('./../modals/user');
exports.getActivity = async (req, res, next) => {
console.log('here');
const activity = await Activity.findById(req.params.id);
res.status(200).json({
status: 'success',
data: {
activity,
},
});
};
exports.addActivity = async (req, res, next) => {
if (req.file) {
let file = {
Ftype: req.file.mimetype.split('/')[0],
name: req.file.filename,
};
req.body.file = file;
}
if (!req.body.location) {
req.body.location = {
coordinates: ['77.206612', '28.524578'],
};
}
if (req.body.votes) {
req.body.votes.diff = req.body.votes.up - req.body.votes.down;
}
req.body.creator = "12345" || "req.userId";
const activity = await Activity.create(req.body);
res.status(201).json({
status: 'success',
data: {
activity,
},
});
};
Also when Content-type:'multipart/form-data, then server console throws Error: Multipart:Boundary not found. When i use Content-type:'application/json', then multer does not work.
I just want to know what is the correct way of uploading files with additional parameters from react-native to nodejs multer. Any suggestions would be a great help!