How can I save an image on the server as a URL? - javascript

EDIT
I removed app.use(fileUpload());. So it finally worked.
But unfortunately in the folder images of the backend I only get these files c43jnfeh734hdfudf.
For this reason, nothing is displayed in the frontend.
const imagePath = req.file.path
const description = req.file.originalname
console.log(imagePath)
console.log(description)
images\c43jnfeh734hdfudf
empty
I have a problem. I would like to save images with a fixed URL on my server.
I found the following code snippet, but unfortunately it doesn't work.
I get the following error in the backend: 'TypeError: Cannot read property 'path' of undefined'.
The following values are 'undefined'. const imagePath = req.file.path const description = req.body.description
How can I save an image as a URL on the server?
Here is the tutorial, where I found the code snippet https://github.com/meech-ward/sammeechward.com_mdx/blob/master/content/articles/uploading-images-express-and-react/index.mdx
React
import { useState } from 'react'
import axios from 'axios'
export default function App() {
const [file, setFile] = useState()
const [description, setDescription] = useState("")
const [image, setImage] = useState()
const submit = async event => {
event.preventDefault()
const formData = new FormData()
formData.append("image", file)
formData.append("description", description)
const result = await axios.post('/api/images', formData, { headers: {'Content-Type': 'multipart/form-data'}})
setImage(result.data.imagePath)
}
return (
<div className="App">
<form onSubmit={submit}>
<input
filename={file}
onChange={e => setFile(e.target.files[0])}
type="file"
accept="image/*"
></input>
<input
onChange={e => setDescription(e.target.value)}
type="text"
></input>
<button type="submit">Submit</button>
</form>
{ image && <img src={image}/>}
</div>
)
}
Backend
const express = require('express')
const fs = require('fs')
const multer = require('multer')
const upload = multer({ dest: 'images/' })
const app = express()
// app.use('/images', express.static('images'))
app.get('/images/:imageName', (req, res) => {
// do a bunch of if statements to make sure the user is
// authorized to view this image, then
const imageName = req.params.imageName
const readStream = fs.createReadStream(`images/${imageName}`)
readStream.pipe(res)
})
app.post('/api/images', upload.single('image'), (req, res) => {
const imagePath = req.file.path
const description = req.body.description
// Save this data to a database probably
console.log(description, imagePath)
res.send({description, imagePath})
})
app.listen(8080, () => console.log("listening on port 8080"))
routes/Test.js
const express = require("express");
const router = express.Router();
module.exports = router;
const auth_util = require("../utilities/auth_util");
const pgclient = require("../app");
const multer = require('multer')
const upload = multer({ dest: 'images/' })
// app.use('/images', express.static('images'))
router.get('/images/:imageName', (req, res) => {
// do a bunch of if statements to make sure the user is
// authorized to view this image, then
const imageName = req.params.imageName
const readStream = fs.createReadStream(`images/${imageName}`)
readStream.pipe(res)
})
router.post('/api/images', upload.single('image'), (req, res) => {
console.log(req.file)
console.log(req.files)
const imagePath = req.file.path
const description = req.body.description
// Save this data to a database probably
console.log(description, imagePath)
res.send({ description, imagePath })
})
// added the lines below
const path = require("path");
router.use(express.static(path.join(__dirname, 'build')));
router.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.js
const express = require("express");
const cors = require("cors");
//const fileUpload = require("express-fileupload");
const session = require("express-session");
const { Pool } = require("pg");
const app = express();
app.use(express.json());
//app.use(fileUpload());
//------------------------------CORS settings------------------------------
var whitelist = [
"http://localhost:3000",
"http://localhost:3001",
];
var corsOptions = {
credentials: true,
exposedHeaders: ["set-cookie"],
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
// callback(null, true)
callback(new Error("Not allowed by CORS!!"));
}
},
};
app.options("*", cors(corsOptions));
const pgclient = new Pool({
user: process.env.DB_USER,
host: process.env.DB_HOST,
database: process.env.DB_DATABASE,
password: process.env.DB_PASSWORD,
port: process.env.DB_PORT,
});
module.exports = pgclient;
app.set("trust proxy", 1);
const testRoute = require("./routes/test");
app.use("/test", cors(corsOptions), testRoute);
app.get("/", cors(corsOptions), (req, res, next) => {
res.send("Welcome");
});
module.exports = app;

First of all, you need to remove express-fileupload. There is no need to use it alongside multer.
To have the correct file with an extension in specified folder, you need to change this part of your code:
remove this line:
const upload = multer({ dest: 'images/' })
change it to:
// routes/Test.js
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'images')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
const upload = multer({ storage: storage })
For conventional and standard way to prevent overwriting the same file names, you need to change filename to this:
filename: function (req, file, cb) {
cb(null, `${Date.now()}-${file.originalname}`)
}

According to this answer, multer uses a kind of cookie in its file uploads and out of date versions of the cookie cause the file upload to fail. Try clearing your browser's cookies.
multer - req.file always undefined
Edit: here is the script working on my end with some images:
I did have to make one minor edit to get the example to work on chrome. To avoid the CORS policy, the front and back end must both be hosted at the same port. So, I added get route to statically serve the react page from the expressjs server:
const express = require('express')
const fs = require('fs')
const multer = require('multer')
const upload = multer({ dest: 'images/' })
const app = express()
// app.use('/images', express.static('images'))
app.get('/images/:imageName', (req, res) => {
// do a bunch of if statements to make sure the user is
// authorized to view this image, then
const imageName = req.params.imageName
const readStream = fs.createReadStream(`images/${imageName}`)
readStream.pipe(res)
})
app.post('/api/images', upload.single('image'), (req, res) => {
console.log(req.file)
console.log(req.files)
const imagePath = req.file.path
const description = req.body.description
// Save this data to a database probably
console.log(description, imagePath)
res.send({ description, imagePath })
})
// added the lines below
const path = require("path");
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(8080, () => console.log("listening on port 8080"))

Related

Node Express 404 error when trying to load image uploaded by multer

Im trying to upload images with multer. Everything has worked before on localhost fine. Images get uploaded and i can view them from the url link the code provides. However once i have uploaded it on a server im starting to get this error : "Cannot GET /marketplace-api/rest-api/image/1650484814178.jpg".
I have not provided link to server/domains to the question in case people say thats the problem.
Here is my code:
const express = require('express');
const app = express();
const multer = require("multer");
const path = require("path");
const db = require('./db');
const cors = require('cors');
const port = 5000;
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true , limit: '50mb'}));
app.use(cors());
app.use("/image", express.static("image"));
let imageName = "";
const storage = multer.diskStorage({
destination: path.join("./image"),
filename: function (req, file, cb) {
imageName = Date.now() + path.extname(file.originalname);
cb(null, imageName);
},
});
const upload = multer({
storage: storage,
limits: { fileSize: 3000000 },
}).single("myImage");
app.post("/marketplace-api/rest-api/upload-image", (req, res) => {
upload(req, res, (err) => {
if (err) {
console.log(err);
} else {
return res.status(201)
.json({ url: "http://link to domains/marketplace-api/rest-api/image/" + imageName });
}
});
});
app.listen(port, () => {
console.log("server run in port", port);
});
ok, few things, 1. you dont have any get functions, which means you cant post to this location, i suggest doing this:
app.get('/', (req, res) => {
res.sendFile(__dirname + "/index.html");
});
and create a file called index.html, go on your site (localhost), and it should work, after that add a form in the html file, it should look something like this
<form action = "/marketplace-api/rest-api/upload-image" method = "POST">
<input type = "file" name="image">
<input type = "submit">
</form>
this will add a basic form where you can upload your photo.
there are a few more stuff to add / change, i will fix everything and make it a repo then send it here

nodejs : nodemon app crashed - waiting for file changes before starting

I was actually following a nodejs course on Udemy and suddenly down the course, the code started breaking and giving some errors. I then tried copying the instructor's code, but still, the problem was the same.
I also followed this answer on StackOverflow itself but the problem remains the same.
I am attaching all the js files below and also the error message from the terminal below:
Error message from the terminal
This is what the file structure looks like
Now the js files:
app.js file:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const errorController = require('./controllers/error');
const app = express();
app.set('view engine', 'ejs');
app.set('views', 'views');
app.use(bodyParser.urlencoded({extended:false}));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(errorController.get404Page);
app.listen(3000);
controllers/error.js file:
exports.get404 = (req, res, next) => {
res.status(404).render('404', { pageTitle: 'Page Not Found' });
};
controllers/products.js file
const Product = require('../models/product');
exports.getAddProduct = (req, res, next) => {
res.render('add-product', {
pageTitle: 'Add Product',
path: '/admin/add-product',
formsCSS: true,
productCSS: true,
activeAddProduct: true
});
};
exports.postAddProduct = (req, res, next) => {
const product = new Product(req.body.title);
product.save();
res.redirect('/');
};
exports.getProducts = (req, res, next) => {
Product.fetchAll(products => {
res.render('shop', {
prods: products,
pageTitle: 'Shop',
path: '/',
hasProducts: products.length > 0,
activeShop: true,
productCSS: true
});
});
};
models/product.js file :
const fs = require('fs');
const path = require('path');
const p = path.join(
path.dirname(process.main.filename),
'data',
'products.json'
);
const getProductsFromFile = cb => {
fs.readFile(p, (err, fileContent) => {
if (err) {
cb([]);
} else {
cb(JSON.parse(fileContent));
}
});
};
module.exports = class Product {
constructor(t) {
this.title = t;
}
save() {
getProductsFromFile(products => {
products.push(this);
fs.writeFile(p, JSON.stringify(products), err => {
console.log(err);
});
});
}
static fetchAll(cb) {
getProductsFromFile(cb);
}
};
routes/admin.js file:
const path = require('path');
const express = require('express');
const productsController = require('../controllers/products');
const router = express.Router();
// /admin/add-product => GET
router.get('/add-product', productsController.getAddProduct);
// /admin/add-product => POST
router.post('/add-product', productsController.postAddProduct);
module.exports = router;
routes/shop.js file:
const path = require('path');
const express = require('express');
const productsController = require('../controllers/products');
const router = express.Router();
router.get('/', productsController.getProducts);
module.exports = router;
util/path.js file:
const path = require('path');
module.exports = path.dirname(process.main.filename);
I am new to backend development, nodejs to be specific. Please help me find my mistake.
In many file you have used process.main.filename, but there is no property named process.name for node.js process, so process.main is undefined. As a result reading the property process.main.filename gives the error.
So, to solve your problem:
Replace every process.main.filename with
process.mainModule.filename OR require.main.filename
(there is difference in both, but it will not matter in your app.)
and see if it works. I guess this is a mistake on your part while writing the code.
Tip: Always try to understand the error using terminal output. That way You can solve most of the problems.

req.body is empty, why?

I want to send some data to my MongoDB database, but in router.post my req.body is empty, if I use stuff that I put in my send function in User(req.body) instead of req.body data will be send to my MongoDB database correctly.
This is my router that I use, router.get work fine, it return database tables correctly on /api page:
const router = require("express").Router();
const User = require("./model/models");
const parser = require("body-parser").json();
router.get("/", async (req, res) => {
const data = await User.find({});
res.json(data);
});
router.post("/",parser,async (req, res) => {
console.log('1')
console.log(req.body)
console.log('2')
parser.v
await User(req.body).save();
res.json({"msg": "ok"});
});
module.exports = router
This is my index.js file code:
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const parser = require("body-parser").json();
var path = require('path');
app.use(express.urlencoded(true));
app.use(express.json());
app.use(parser);
app.use('/',require("./routes/routes"))
app.use(express.static(__dirname +'/public'))
app.use("/api", require('./data/api'))
app.listen(5000,function(){
console.log('server is alive')
})
This is function that what I use to send data:
const btn1 = document.getElementById('btnEnter')
let Login = "123"
btn1.addEventListener('click' ,e=>{
send({newsTxT : "someTextHere",newsZag:"someZag",author:"SomeAuthor"})
})
const send = async(body) => {
let res = await fetch("/api", {
method: "post",
header: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify(body)
});
let data = await res.json();
console.log(data)
}
The only weird thing I see is that you are using a json body-parser and also the express.json() both technically do the same, but body-parser is deprecated so it might be causing a bug.
Also you don't have to import it again in the routes, placing app.use(express.json()) at index.js will make it work for all endpoints/routes.
See how this refactor goes:
const router = require('express').Router()
const User = require('./model/models')
router.get('/', async (req, res) => {
const data = await User.find({})
res.json(data)
})
router.post('/', async (req, res) => {
console.log('1')
console.log(req.body)
console.log('2')
await User(req.body).save()
res.json({ 'msg': 'ok' })
})
module.exports = router
index.js
const express = require('express')
const app = express()
var path = require('path')
app.use(express.urlencoded(true))
app.use(express.json())
app.use('/', require('./routes/routes'))
app.use(express.static(__dirname + '/public'))
app.use('/api', require('./data/api'))
app.listen(5000, function () {
console.log('server is alive')
})
The following worked fine:
const express = require("express")
const app = express()
const router = express.Router()
router.use(express.json())
app.use(router)
router.post('/api/user', function(req, res) {
// ...
}
I see the difference may be using the: app.use(router)
Note that in the above code the statement:
router.use(express.json())
can be replaced with (using the body-parser):
const bodyParser = require('body-parser')
router.use(bodyParser.json())
This worked fine with express version 4.17.1, body-parser version 1.19.0 and NodeJS version 12.18.3

Empty body Api rest express node js

I'm trying to make an API using express in nodejs.
This api should get a request with a photo and post that photo to firebase storage.
The main problem is that for some reason the body of the requests I send are empty.
This is the code for the server:
const express = require("express");
const morgan = require("morgan")
const cors = require('cors')
const app = express();
// Settings
app.set('port', process.env.PORT || 3000)
app.set('json spaces', 4)
// middleware
app.use(morgan("dev"))
app.use(express.json())
app.use(express.urlencoded({extended: true}))
app.use(cors({origin: "http://localhost:3001"}))
// routes
app.use(require("./routes/index"))
app.listen(app.get('port'), () => {
console.log("Server using port " + app.get('port'));
});
Routes
const { Router } = require('express')
const router = Router()
router.post('/postImage', async (req, res) => {
try {
const image = req.body
console.log(image) // Here I only get an epty object "{}"
return res.status(200).json(image)
}
catch(error) {
console.log(error)
return res.status(500).json({error})
}
})
module.exports = router
Client side
const postImage = async (image) => {
console.log(image) // Here I get the image data
const response = await fetch("http://localhost:3000/postImage", {
method: "POST",
body: {message: "image"}
})
const data = await response.json()
}
I've tried using body-parser but it seems to be deprecated
you have to send an image from the front end in formData.
const data = new FormData();
data.append('myFile', 'Image Upload');
In back end use multer to upload file to server.
first install multer by : npm i multer
const multer = require("multer");
//Configuration for Multer
const upload = multer({ dest: "public/files" });
app.post("/api/uploadFile", upload.single("myFile"), (req, res) => {
// Stuff to be added later
console.log(req.file);
});
Here is a proper Guide to upload file using multer express js

what is the way of saving image path to mongodb?

I am developing REST API using nodeJS, express, mongoose etc with mongodb. I am uploading file and saving it to a folder using multer. Now I want to save the path of the file to a mongodb document.
However, I am saving data to mongodb using mongoose schema. First I created the model. When a post request is made, I read it using bodyParser (req.body) and save this object by creating new instance or more shortcut.
Product.create(req.body).then(function(product){
res.send(product);
}).catch(next);
But when I am using multer to upload a file and want to save the path to the model I cant do it using create() function. So what is the way ??
In the MongoDB we can store single or multiple images. For storing multiple images I am using productPictures array.
1: First, create the Product model
const mongoose = require('mongoose');
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
},
productPictures: [{ img: { type: String } }],
});
module.exports = mongoose.model('Product', productSchema);
2: Create the product controller
const Product = require('../models/product');
exports.createProduct = (req, res) => {
const { name} = req.body;
let productPictures = [];
if (req.files.length > 0) {
productPictures = req.files.map((file) => {
return { img: file.filename };
});
}
const product = new Product({
name,
productPictures,
});
product.save((error, product) => {
if (error) return res.status(400).json({ error });
if (product) {
res.status(201).json({ product });
}
});
};
3: Create products route file
I am using nanoid to generate a unique name for images
Create uploads folder inside src folder
const express = require('express');
const path = require('path');
const multer = require('multer');
const { nanoid } = require('nanoid');
const { createProduct } = require('../controllers/product');
const router = express.Router();
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(path.dirname(__dirname), 'uploads'));
},
filename: function (req, file, cb) {
cb(null, nanoid() + '-' + file.originalname);
},
});
const upload = multer({ storage: storage });
router.post(
'/products/create',
upload.array('productPicture'), // for storing single image : upload.single('productPicture')
createProduct
);
module.exports = router;
4: Create server.js file
const env = require('dotenv');
const express = require('express');
const mongoose = require('mongoose');
const app = express();
// routes
const productRoutes = require('./routes/product');
env.config();
mongoose
.connect(`${process.env.MONGO_URI}`, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => {
console.log('Database connected');
});
// Body parser (You can you **body-parser**)
app.use(express.json());
app.use('/api', productRoutes);
app.listen(process.env.PORT, () => {
console.log(`Server is running on port ${process.env.PORT}`);
});
5: Finally you can create product using postman
Here you can upload the image into some destination you want, this is for the reference for more details information including how to access stored images in Mongodb and you can see the documentation here about multer.
express = require('express')
, router = express.Router()
, MongoClient = require('mongodb').MongoClient
, ObjectId = require('mongodb').ObjectId
, fs = require('fs-extra')
// Your mongodb or mLabs connection string
, url = 'mongodb://username:password#yourinstanced.mlab.com:29459/yourdb'
, multer = require('multer')
, util = require('util')
, upload = multer({limits: {fileSize: 2000000 },dest:'/uploads/'})
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
if (req.file == null) {
// If Submit was accidentally clicked with no file selected...
)} else {
MongoClient.connect(url, function(err, db){
// this landing will give you any option of file information that you can collect
console.log('landing here', req.file)
// read the img file from tmp in-memory location
var newImg = fs.readFileSync(req.file.path);
// encode the file as a base64 string.
var encImg = newImg.toString('base64');
// define your new document
var newItem = {
contentType: req.file.mimetype,
size: req.file.size,
name: req.file.originalname,
path: req.file.path
};
db.collection('yourcollectionname')
.insert(newItem, function(err, result){
if (err) { console.log(err); };
var newoid = new ObjectId(result.ops[0]._id);
fs.remove(req.file.path, function(err) {
if (err) { console.log(err) };
res.send(newItem);
});
});
});
}});
If using multer you will get uploaded files path in req.file.path and you just need to save that in your database.

Categories