How to get request extension in express? - node.js

How to understand if somebody requests image or file in express? For example:
https://example.com/image.png
https://example.com/file.js

app.get("/:fileName", (req, res) => {
const file = req.params.fileName.split(".");
const fileExtension = file[file.length-1];
const imageExtensions = ["png", "jpg"];
if(imageExtensions.includes(fileExtension) {
console.log("It's an image");
} else if (fileExtension === "js") {
console.log("It's a javascript file");
}
return res.send();
});
But i would recommend to just separate the routes per resource type, for example:
app.get("/img/:fileName", (req, res) => {
console.log(`Getting image ${req.params.fileName}`);
return res.send();
});
app.get("/js/:fileName", (req, res) => {
console.log(`Getting JS file ${req.params.fileName}`);
return res.send();
});

Once the server received the request, you can check for the extension of the url and later process it. [need more information to know exactly what you need]

Related

Node.js (Express) Dynamically Inserting Meta Tags Error: Uncaught SyntaxError: Unexpected token '<'

My React website served using Express from the back works with:
app.use(express.static(path.resolve(__dirname, './client/build')));
That said, I'm refactoring the backend code such that each route adds dynamic meta tags and serves up the website separately with this:
app.get('/', async (req, res) => {
const pathToIndex = path.resolve(__dirname, './client/build', 'index.html');
try {
// try dynamically inserting title meta tag
fs.readFile(pathToIndex, 'utf8', function (err, data) {
if (err) {
return console.log(err);
}
data = data.replace(/\$OG_TITLE/g, "ABC");
res.send(data);
});
} catch(err) {
res.sendFile(pathToIndex);
}
});
The above refactor causes the following error:
Here's my folder structure:
Any clue what the issue could be?
Try following code
app.get("/", async (req, res) => {
const pathToIndex = path.resolve(__dirname, ".", "index.html");
const fileData = fs.readFileSync(pathToIndex, { encoding: "utf8" });
// data = fileData.replace(/\$OG_TITLE/g, "ABC");
data = fileData.replace(/App/g, "ABC");
console.log(data);
return res.send(data);
});

A super simple Multer question, nested file uploading

I'm trying to do an image upload with Multer and Express. Doing just an image upload is going fine and everything works, the problem is, I want to send more than just one photo. Let me explain. I got the most basic form ever, not worth sharing. Then when submitting the form with JUST an image, the axios request looks like this:
async onSubmit() {
const formData = new FormData();
formData.append('file', this.person.personData.file)
this.obj.file = formData
try {
await axios.post('/projects/new', this.obj.file);
this.message = 'Uploaded';
} catch (err) {
console.log(err);
this.message = 'Something went wrong'
}
},
The post route in Express to receive the image looks like this:
personRoutes.post('/new', upload.single('file'), (req, res) => {
console.log('BODY: ', req.body)
console.log('REQ.FILE: ', req.file)
const person = new Person({
personData: {
file: req.file.path
}
});
person.save()
.then(result => {
console.log('YES', result)
res.redirect('/projects')
})
.catch(err => {
console.log('KUT', err)
})
});
req.file is the upload.single('file') file. Req.body will hold the text fields, if there were any. Ez Pz, so far so good. Now, where things get a bit sketchy is, what if I wanted to upload more than just one photo? So my obj object would not only hold a file property but a few others aswell. Currently I am directly sending the formData file with
await axios.post('/projects/new', this.obj.file);
But if my obj contained more than just a file, I would have to to this:
await axios.post('/projects/new', this.obj);
But what in the world should my Express post route look like? Because req.file will now (as far as I know) forever be undefined because file is not defined inside req object. It is defined in req.body object. Accessing the file as req.obj.file won't do anything. Any help would be very much appreciated. I don't even know if it is possible. And if not, what other options do I have?
Thanks in advance!
upload.array('file') should work. any number of files will be received.
here is an example:
multer code:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads')
},
filename: (req, file, cb) => {
cb(null, "image"+Date.now()+file.originalname);
}
});
const fileFilter = (req,file,cb)=>{
if(file.mimetype==="image/jpeg" || file.mimetype==="image/png"){
cb(null, true);
}else{
cb(new Error("File type is not acceptable"),false);
}
}
const uploadImages = multer({storage:storage,
limits:{
fileSize: 1024*1024*10
},
fileFilter:fileFilter}).array("shopImage");
app.post code:
app.post("/shop", function(req,res){
uploadImages(req,res,function(err){
if(err){
console.log(err);
res.status(400).json({message:err.message});
}else{
console.log(req.files);
console.log(req.body);
....
}
});
....
})

Axios post isn't handling the response

I am uploading images to Cloudinary and want to retrieve the image url after it is uploaded. It is uploading correctly and I can console.log the url on server side but afterwards the response is not handled in the axios call on the client side and no error messages appear.
My client:
submitFile = () => {
var formData = new FormData();
formData.append('image', this.state.file, 'tmp_name');//this.state.file is not correct format compared to postman constructed
axios.post('http://localhost:3000/upload', formData).then(function(response) {
console.log(response);
});
}
My server:
server.post('/upload', async (req, res, next) => {
const upload = multer({ storage }).single('image')
upload(req, res, function(err) {
if (err) {
return res.send(err)
}
const path = req.file.path
cloudinary.uploader.upload(
path,
{ public_id: `${filename()}` },
async function(err, image) {
if (err) return res.send(err)
console.log('file uploaded to Cloudinary')
// remove file from server
const fs = require('fs')
fs.unlinkSync(path)
}
).then(result => {res.send(result)})
})
Again I want to just be able to view the response and save it but everything after then .then doesn't execute.
You need to remove bracket in then of server code
server.post('/upload', async (req, res, next) => {
/* upload code*/
).then(result => res.send(result))
})
OR
Add return in then of server code
server.post('/upload', async (req, res, next) => {
/*upload code*/
).then(result => { return res.send(result)})
})

Calling an API endpoint from within another route in Node / Express

I have myRoute.js with a route (GET) defined and I want to call an api endpoint from another route (api.js), and I'm not sure what the right way to do this is. The api.js route is working properly (image and code below).
api.js
router.get('/getGroups/:uid', function(req, res, next) {
let uid = req.params.uid;
db.getAllGroups(uid).then((data) => {
let response =[];
for (i in data) {
response.push(data[i].groupname);
}
res.status(200).send(response);
})
.catch(function (err) {
return err;
});
});
works as expected:
myRoute.js
I would like when a user goes to localhost:3000/USER_ID that the route definition gets information from the api. Psuedo code below (someFunction).
router.get('/:uid', function(req, res, next) {
let uid = req.params.uid;
let fromApi = someFunction(`localhost:3000/getAllGroups/${uid}`); // <--!!!
console.log(fromApi) ; //expecting array
res.render('./personal/index.jade', {fromApi JSON stringified});
});
Not sure if i understand you correct but anyway i will try to help. So you have an api like
router.get('/getGroups/:uid', function(req, res, next) {
let uid = req.params.uid;
db.getAllGroups(uid).then((data) => {
let response =[];
for (i in data) {
response.push(data[i].groupname);
}
res.status(200).send(response);
})
.catch(function (err) {
return err;
});
});
If you would like to reuse it you can extract a function from the code above like so:
async function getAllGroupsByUserId(uid){
const result = [];
try{
const data = await db.getAllGroups(uid);
for (i in data) {
result.push(data[i].groupname);
};
return result;
}
catch(e) {
return e;
}
}
And then reuse it in your api & anywhere you want:
router.get('/getGroups/:uid', async function(req, res, next) {
const uid = req.params.uid;
const groups = await getAllGroupsByUserId(uid);
res.status(200).send(groups);
})
Same you can do in your another route:
router.get('/:uid', async function(req, res, next) {
const uid = req.params.uid;
const fromApi = await getAllGroupsByUserId(uid); // <--!!!
console.log(fromApi) ; //expecting array
res.render('./personal/index.jade', {fromApi JSON stringified});
});
Seems like pretty clear :)
I would use fetch for this. You can replace someFunction with fetch, and then put the res.render code in a .then(). So, you would get this:
const fetch = require("node-fetch");
router.get('/:uid', function(req, res, next) {
let uid = req.params.uid;
fetch('localhost:3000/getAllGroups/${uid}').then(res => res.json()).then(function(data) {
returned = data.json();
console.log(returned); //expecting array
res.render('./personal/index.jade', {JSON.stringify(returned)});
});
});
A more robust way with error handling would be to write something like this:
const fetch = require("node-fetch");
function handleErrors(response) {
if(!response.ok) {
throw new Error("Request failed " + response.statusText);
}
return response;
}
router.get('/:uid', function(req, res, next) {
let uid = req.params.uid;
fetch('localhost:3000/getAllGroups/${uid}')
.then(handleErrors)
.then(res => res.json())
.then(function(data) {
console.log(data) ; //expecting array
res.render('./personal/index.jade', {JSON.stringify(data)});
})
.catch(function(err) {
// handle the error here
})
});
The ideal way would be to abstract your code into a method so you aren't calling yourself, as The Reason said. However, if you really want to call yourself, this will work.

Can't get params from get request - Node JS, Angular

I have this angular method that gets features. I only need the features that have the releaseid that I pass with paramters.
getFeatures() {
this.route.params.subscribe(params => {
this.featureService.getFeatures(params['releaseid']).subscribe(res => {
this.features = res;
})
});
}
My service (featureService):
getFeatures(releaseId) {
const uri = 'http://localhost:4000/features';
return this
.http
.get(uri, {params: {releaseId: releaseId}})
.map(res => {
return res;
});
}
My nodejs route
featureRoutes.route('/features').get(function (req, res) {
console.log(req.body.params);
});
But the req.body.params is undefined.
Any help on this?
Try this
Service (featureService):
getFeatures(releaseId) {
const uri = 'http://localhost:4000/features?releaseId=' + releaseId;
return this.http.get(uri);
}
Nodejs route:
featureRoutes.route('/features').get(function (req, res) {
console.log(req.params); // should contain your releaseId
});
You should now be able to get the releaseId in your node backend.
I found it. in my routes i had to do:
console.log(req.query.releaseId)

Resources