Multer takes the files i upload and puts it inside the file object so we can access it through the file but then the req.body.image is empty and i want to be able to pass the file.originalname to the req.body.image as path to the stored disk location. Now, i am working with multiple file here so i want to store their paths in the req object and access it inside another middle ware.
I tried something like this
req.body.image.push(`path/${file.originalname}`)
which returns an error
TypeError: Cannot read property 'push' of undefined
TypeError: Cannot read property 'push' of undefined
It looks like req.body.image isn't an Array but undefined when you're using push().
When multer adds a single file to the request object, it adds them to the req.file property. You can then access req.file in subsequent middleware like in the below example. If you have multiple uploaded files then you would access the File Array req.files and iterate through the collection to access each file object.
In your above code, you're modifying the req.body object and adding the property image, I wouldn't recommend changing the req.body object. It is good practice to not mutate things like the request headers or body. Instead, you can add a new property req.image to the request object.
The below example uses Router Middleware to encapsulate the upload logic, (which should be kept to a single route usually) and then adds that middleware to an Express Server.
imageUploadRouter.js
// imageUploadRouter.js
const router = require('express').Router()
const multer = require('multer')
const upload = multer({dest: 'uploads/'})
router.use(upload.single('image'))
router.use((req, res, next) => {
if (!Array.isArray(req.image)) {
req.image = []
}
if (req.file) {
req.image.push(`path/${req.file.originalName}`)
}
return next()
})
// add some additional routes for logic
router.post('/', (req, res) => {
// do something and respond
// you can access req.image here too
return res.sendStatus(201)
})
module.exports = router
server.js
// server.js
const express = require('express')
const ImageUploadRouter = require('./imageUploadRouter')
const server = new Express()
const port = process.env.PORT || 1337
server.use('/images', ImageUploadRouter)
server.listen(port, () => console.log(`Lisening on ${port}`))
Related
Hey i want to get the data from my json file and then display it in html, but first i will just console.log it. how do i exactly do that??
the json file will be updated as its the users input
varer.json
[{"id":"aa","varer":"aa","pris":""},{"id":"aa","varer":"aa","pris":""}]
varer-controller
const varerModel = require("./../models/varer");
const express = require("express");
const router = express.Router();
router.get("/getproducts", (req, res) =>{
var products = JSON.parse(varerModel)
console.log(products)
res.send(products)
})
You don't need to JSON.parse as it's already a JSON and can be directly used.
I'm trying to dynamically create folders when user loads a file (this is because I need to store every user files separately so there's no conflict if a file is deleted) and create the file path in my computer so I can store it in my many to many relationship table in the database (users can have many files and many files can belong to different users, that's why I can't store them together) but I cannot get this with my current logic. I could create different name with timestamps but it would get messy.
I'm using multer and Express. The form data that's been sent is the one on the attached image.
const express = require('express');
const app = express();
const multer = require('multer');
const bodyParser = require('body-parser');
const fs = require('fs');
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: false }));
let storage = multer.diskStorage({
destination: function (req, file, cb) {
//req.body is empty
let path = `./public/uploads/${req.body.id}`;
if (!fs.existsSync(path)) {
fs.mkdirSync(filesDir);
}
cb(null, path);
},
filename: function (req, file, cb) {
cb(null, `${file.originalname}`)
}
})
let upload = multer({storage:storage});
var cpUpload = upload.fields([{ name: 'file', maxCount: 1}, { name: 'id'}]);
router.post('/uploadSingFile', cpUpload,(req,res)=>{
console.log(req.body); req.body is ok
res.send({status:200});
});
Somehow the request object doesn't have the body in the destination function but does in the post request. I thought this would work given the way middlewares work in Node, the storage function should have the same request object that the post request has.
You can use newly generated uuid for filenames to have it unique inside the folder. For the folder name, instead of getting it from request body(req.body.id), use something like userId which can make sure the folder belongs to particular user.
I have a bit of an issue when i try to create an object prototype in my node/express app.
I first start by creating the prototype like so:
Object.prototype.printObject = function () {
return console.log(this);
}
Now the issue is when I call this function. For instance when i call the function like this:
let request = {1:2}
request.printObject();
*//Logs {1:2}*
No error occurs. Yet when I call the function like this:
let request = req.body
request.printObject();
My program crashes with error: TypeError: request.printObject is not a function
Does anyone have any clue as to why this occurs?
if you require('body-parser')? or req.body is undefined,you should do this first
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
You have added the 'printObject' method on the prototype of Object. So if req.body is an Object, you should be able to call the method.
Try checking the type of req.body using console.log(typeof req.body) to verify that it is an Object.
If it is not, you should use the node module 'body-parser' to populate req.body with the parsed body content.
For example, parts of your server code might look like this:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json()); // Data is being sent to the server in JSON format
app.post('/my/endpoint', function(req, res){
req.body.printObject();
});
The 'body-parser' module supports other formats as well. I used JSON as an example. You can find everything they support here: https://www.npmjs.com/package/body-parser
Insteat of trying to prototype any Object, you could create a middleware function like so:
app.use(function (req, res, next) {
console.log('req');
//you could also add any function to req,even so thats not a common thing to do
req.printObject = function { ... }
next();
});
Probably the problem with your approach is, that you add the function to the Object prototype after the request object was created.(EDIT: This is wrong, see comments)
I keep getting an error that says it cannot find the module reddit.js. I have a folder called "routes" (without quotes) in my directory. In that folder I have reddit.js which is middleware. On the first file below, I did change it to var reddit = require('./routes/reddit.js') and I received the error messsage that says "throw new TypeError('Router.use() requires middleware function but got a
^
TypeError: Router.use() requires middleware function but got a Object
at Function.use "
When I keep the code as shown below I get this error:
Error: Cannot find module 'reddit.js'
my app.js file contains the following code:
var express = require('express');
var app = express();
var fs = require('fs');
var reddit = require('reddit.js');
app.use ('/', reddit);
app.use(express.static('public'));
app.use(express.static('public/js'));
app.use(express.static('public/images'));
app.use(express.static('routes'));
my reddit.js file contains the following code:
var express = require ('express');
var request = require ('request');
var reddit = express.Router();
reddit.get(function (req, res, next) {
request('https://www.reddit.com/r/Showerthoughts/hot.json',function(error, response, body){
console.log(body);
var docs = JSON.parse(body).response;
//var titles = [];
console.log(docs);
res.send(docs);
next;
});
});
what am I doing wrong?
Mentioned below are the list of things that are not correct
You don't need to have .js extensions for including files. Use require('/path/to/reddit'); instead of require('reddit.js');
You need to export the router instance in reddit.js. Add module.exports = reddit; at the end of the file.
Don't call next() after sending out the response using res.send(docs);
Routes are not static content. Remove app.use(express.static('routes'));
app.use(express.static('/public')); handles all static content inside the /public folder. You do not need to add app.use(express.static('/public/js'));
Being a newbie in Nodejs, I jumped right into writing a simple app without really reading up on good security practices. I just found out that using bodyParser() for all routes is actually a bad thing because it allows for DOS attack using multipart files.
A recommended fix is to only load specific modules depending on the route. ie, for multipart fileupload, use multipart. For regular POST without file uploads (ie, text form submission), use express.json(), express.urlencoded().
Or another option is to use busboy with connect-busboy. But the thing I'm confused on is how I can specify which route should handle multipart data and which should not? Otherwise, wouldn't I have the same problem as with bodyParser?
Furthermore, busboy docs says it does not handle GET:
If you find that req.busboy is not defined in your code when you expect it to be, check that the following conditions are met. If they are not, req.busboy won't be defined:
1. The request method is not GET or HEAD
So, I'm even more confused how I would parse params in a GET. I think bodyParser does this for me so I could access data with req.params.
For example, how would I migrate away from bodyParser() to busboy/connect-busboy with this simple app:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
app.use(bodyParser.json());
var busboy = require('connect-busboy');
app.use(busboy());
// How to use busboy to prevent multipart files here?
app.post("/form_data_no_fileupload", function(req, res) {
var somedata = req.body.somedata;
});
// Use busboy to handle both regular form data + fileuploads
app.post("/form_data_AND_fileupload", function(req, res) {
});
// What would handle GET without bodyparser?
app.get("/get_something", function(req, res) {
var params = req.params;
});
http.listen(3000, function() {});
[How] I can specify which route should handle multipart data and which should not?
All of Express' routing methods allow for providing middleware specific to the route. This includes Router methods.
app.METHOD(path, callback [, callback ...])
Depending on the body expected for an individual route, you can use different modules to handle each of them (rather than applying them to the entire application with app.use()).
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
var busboy = require('connect-busboy');
app.post("/form_data_no_fileupload",
bodyParser.urlencoded(),
function(req, res, next) {
// check that the request's body was as expected
if (!req.body) return next('route'); // or next(new Error('...'));
// ...
});
app.post("/form_data_AND_fileupload",
busboy({
limits: {
fileSize: 10 * 1024 * 1024
}
}),
function(req, res, next) {
// check that the request's body was as expected
if (!req.busboy) return next('route'); // or next(new Error('...'));
// ...
});
// ...
Furthermore, busboy docs says it does not handle GET.
So, I'm even more confused how I would parse params in a GET.
Busboy and BodyParser are designed for reading in and parsing the request's body, which GET and HEAD requests aren't expected to have.
For such requests, parameters can only be passed within the query-string within the URL, which Express parses itself. They're available via req.query.
app.get('/get_something', function () {
console.log(req.originalUrl);
// "/get_something?id=1
console.log(req.query);
// { id: "1" }
});
req.params represents any placeholders matched in the path by the route. These are available for any route, regardless of the method.
app.get('/thing/:id', function (req, res) {
console.log(req.originalUrl);
// "/thing/2"
console.log(req.params);
// { id: "2" }
});