How to implement conditional upload file using multer? - express

I have 2 input type="file" on a single form and I want file from left input upload into "left" folder and right to "right"
but how could I know what file was uploaded from right or left input?
const express = require("express");
var bodyParser = require("body-parser");
const app = express();
const multer = require("multer");
app.get("/", (req, res) => {
res.send(`
<form action="/upload" enctype="multipart/form-data" method="post">
<input type="file" name="left"/><br>
<input type="file" name="right" /><br>
<button type="submit">send</button>
</form>
`);
});
app.post("/upload", function (req, res, fields) {
const storage = multer.diskStorage({
destination: function (req, file, cb) {
if (true /*if from input name left*/) {
cb(null, "left");
} else {
//if from input name right
cb(null, "right");
}
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
});
const upload = multer({
storage: storage,
}).fields([{ name: "left" }, { name: "right" }]);
upload(req, res, (err) => {
if (err) throw err;
});
});
app.listen(3000);

You are using an upload with fields like this const upload = multer({ storage: storage, }).fields([{ name: "left" }, { name: "right" }]);
and it is supposed for the field names to be identical to form-data appended values,
so all you need to do is to access the request files correctly like following:
for the 'left' file input you access the uploaded file with:
req.files['left'][0]
and for the 'right' file input you also can access it the same way:
req.files['right'][0]
[

Related

How to get multipart/form-data?

when I submit the form to the Submit form button, everything works and the uploaded file is logged into the server console, but why does the Multipart: Boundary not found error occur when I click on Submit using fetch
const express = require("express");
var bodyParser = require("body-parser");
const app = express();
const multer = require("multer");
const fileStorageEngine = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./images");
},
filename: (req, file, cb) => {
cb(null, Date.now() + "--" + file.originalname);
},
});
const upload = multer({ storage: fileStorageEngine });
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(bodyParser.text());
app.get("/", (req, res) => {
res.send(`
<form action="/push" method="POST" enctype="multipart/form-data">
<input type="file" name="image" />
<button type="submit">Submit form</button>
<button onclick="send(event)" type="submit">Submit using fetch</button>
</form>
<script>
function send(event) {
event.preventDefault();
let formData = new FormData(event.currentTarget.parentElement);
fetch("/push", {
body: formData,
headers: {
"Content-Type": "multipart/form-data",
},
method: "POST",
}).then((data) => console.log(data));
}
</script>
`);
});
app.post("/push", upload.single("image"), (req, res) => {
console.log(req.file);
});
app.listen(3000);
I suppose you want to upload an image? to do so you will need to pass three parameter in your fetch request uri , type and name in your formdata. as an exemple :
fetch("/push", {
body: {uri :formData.uri ,
type: formData.type,
name: forData.name}
headers: {
"Content-Type": "multipart/form-data",
},
method: "POST",
}).then((data) => console.log(data));
}

Trouble uploading file in Vue frontend

When I try to upload a user photo with Vue, the formData just seems to be an empty object. The Multer middleware then fails because there is no req.file for it read.
User.vue
<form enctype="multipart/form-data">
<div class="pl-3 label">User Photo</div>
<v-file-input
accept='image/*'
label="Upload Photo"
v-model="photo"
></v-file-input>
<v-btn class="mr-5" color="blue lighten-3" #click="submit">
save changes
</v-btn>
export default {
data: () => ({
photo: null
}),
methods: {
submit() {
let formData = new FormData();
if (this.photo) {
formData.append('photo', this.photo)
}
this.$store.dispatch('updateMe', {
photo: formData
});
}
}
};
Vuex Store
export default new Vuex.Store({
state: {
photo: null
},
mutations: {
setUpdatedUser(state, payload) {
state.name = payload.name;
state.email = payload.email;
state.photo = payload.photo;
}
},
actions: {
async updateMe({ commit, getters }, payload) {
let id = localStorage.getItem('userId');
let user = {
photo: payload.photo
};
try {
let token = getters.token;
const response = await axios.patch(
`http://localhost:3000/api/v1/users/updateMe`,
user,
{
headers: { Authorization: 'Bearer ' + token }
}
);
commit('setUpdatedUser', response.data.updatedUser);
} catch (err) {
console.log(err);
}
}
}
User Controller
const multerStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/users');
},
filename: (req, file, cb) => {
console.log(file)
const ext = file.mimetype.split('/')[1];
cb(null, `user-${req.user.id}-${Date.now()}.${ext}`);
}
});
const multerFilter = (req, file, cb) => {
if (file.mimetype.startsWith('image')) {
cb(null, true);
} else {
cb(new AppError('Not an image. Please upload only images.', 400), false);
}
};
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter
});
exports.uploadUserPhoto = upload.single('photo');
Most other examples I have compared to do not use v-model for the input binding. Does that make a difference?
In an application where I am handling file uploads the files get posted to the node backend.
I also v-model in my component so that shouldn't be the problem.
Frontend method:
upload() {
const data = new FormData()
data.append('file', this.file, this.file.name) // Filename is optional
data.append('additionalInformation', this.additionalInformation)
axios.
post('/api/v1/upload/', data)
.then(response => /* response handling */)
.catch(error => /* error handling */)
}
The node endpoint looks like this:
app.post('/api/v1/upload/', multer().single('file'), (request, response) => {
upload(request.body, request.file, response, config)
})
Reference: FormData.append()

Express file upload using multer file is undefined always

I have tried to make an api to upload files in express using multer middleware but the request.file is undefined.
the express code is given below,
const express = require("express");
var multer = require('multer');
const cors = require("cors");
var app = express();
app.use(cors({ origin: true }));
const multerMid = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024,
},
});
app.post('/saveFile', multerMid.single('dp'), (request,response)=>{
try{
var dp = request.file;
if(dp)
{
return response.send("file uploaded");
}
else{
return response.send("No file uploaded");
}
}catch(error)
{
return response.send(error.errorMessage);
}
});
exports.app = functions.https.onRequest(app);
No file uploaded
this is what I always receive when I post a file to the route using the following html.
<html>
<head>
</head>
<body>
<form action = "<server>/saveFile" method="post" enctype="multipart/form-data">
<input type="file" name="dp"/>
<input type="submit" value="Save">
</form>
</body>
</html>
I need to upload the file to file to firebase storage thats why I don't use a static storage location in the multer object,
I am stuck please help.
Here a middleware needs to be defined
app.post('/saveFile', multerMiddleWare, (request,response)=>{...});
const multerMiddleWare = (req, res, next) => {
multerMid(req, res,
(error) => {
if (!error) return next();
return next('error');
});
};
const multerMid = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024,
},
}).single('dp');

How to use twilio with dynamic routes in nuxt

Hoping I can explain this clearly and someone has some insight on how I can solve this.
I am trying to enter a input then have a text message delivered to the number that was entered. That simple.
On the homepage, I have an input component with:
<template>
<form class="right-card" #submit.prevent="submit">
<input v-model="search" />
<button class="clear" type="submit" v-on:click="submit"></button>
</form>
</template>
With this function set as a method to pass the param
export default {
data () {
return {
search: ''
}
},
methods: {
submit: function (event) {
this.$router.push(`sms/${this.search}`)
}
}
}
Then I have a /sms page located in pages/sms/_sms.vue which is landed on once the form is submitted
<template>
<div>
<h1>Success Page {{phoneNumber}} {{$route.params}}</h1>
<KeyboardCard/>
</div>
</template>
<script>
import KeyboardCard from '~/components/KeyboardCard.vue'
import axios from '~/plugins/axios'
export default {
asyncData ({ params, error }) {
return axios.get('/api/sms/' + params.sms)
.then((res) => {
console.log(res)
console.log(params)
return { phoneNumber: res.data }
})
.catch((e) => {
error({ statusCode: 404, message: 'Sms not found' })
})
},
components: {
KeyboardCard
}
}
</script>
And finally within api/sms/sms.js I have this on express running.
(note my API keys are replaced with placeholder)
router.get('/sms/:sms', (req, res, next) => {
console.log('express reached')
const accountSid = 'ACCOUNTSIDPLACEHOLDER'
const authToken = 'AUTHTOKENPLACEHOLDER'
const client = require('twilio')(accountSid, authToken)
client.messages.create({
to: '14169190118',
from: '+16477993562',
body: 'This is the ship that made the Kessel Run in 14 parsecs?!'
})
.then((message) => console.log(message.sid))
})
How can I pass the parameter.sms within the to field in my /api/routes/sms.js
Expected: When user enters # into the input how can the api/sms/:sms be called dynamically to the number that was typed in the input component?
Thanks in advance if anyone see's whats going on here :)
Edit: I have my middleware defined in the nuxt.config file, like so:
serverMiddleware: [
// API middleware
'~/api/index.js'
]
and my api/index.js file has:
const express = require('express')
// Create express instnace
const app = express()
// Require API route
const sms = require('./routes/sms')
// Import API Routes
app.use(sms)
// Export the server middleware
module.exports = {
path: '/api',
handler: app
}
I guess this is more an Express.js related question than a Vue.js question.
You can use the passed sms param from your request, like this:
router.get('/sms/:sms', (req, res, next) => {
console.log('express reached')
const accountSid = 'ACCOUNTSIDPLACEHOLDER'
const authToken = 'AUTHTOKENPLACEHOLDER'
const client = require('twilio')(accountSid, authToken)
client.messages.create({
to: req.params.sms,
from: '+16477993562',
body: 'This is the ship that made the Kessel Run in 14 parsecs?!'
})
.then((message) => console.log(message.sid))
})

Vue JS and Multer

<template>
<v-app id="inspire" dark >
<v-layout v-for = "post in posts" :key = "post.id">
<v-flex xs3>
<v-card >
<v-card-media>
<img
:src = "post.postImage">
</v-card-media>
<v-card-title>
{{post.description}}
</v-card-title>
</v-card>
</v-flex>
</v-layout>
</v-app>
</template>
<script>
import PostService from '#/service/PostService'
export default {
data(){
return {
posts: []
}
},
mounted (){
this.getPosts()
},
methods: {
async getPosts() {
const response = await PostService.fetchPosts()
this.posts = response.data.posts
}
}
}
</script>
const multer = require('multer');
const Post = require('./models/post')
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './uploads/');
},
filename: (req, file, cb ) => {
cb(null, Date.now() + file.originalname);
}
})
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,
fileFilter,
limits: {
fileSize: 1024 * 1024 * 5
}
});
app.get('/posts', (req, res) => {
Post.find({},'postImage description', (error, posts) => {
if(error) {
console.log(error)
}
res.send({
posts
})
}).sort({_id: -1})
})
Hi all, i was about to display images using multer on my front end. but it does only show imagelink or image destination, but i already added some images in my backend. So how can i show images to my front-end using vue dynamically. I did use v-for for each data in my database. what should i input to my v-card-media to get images dynamically.