Vue - How to display image received from backend API? - node.js

I'm building a webApp in MEVN stack (Mongo, Express, Vue, Node).
In my backend, I have a controller (./backend/controllers/screenshots.controller.js) downloading an image from an external REST API. The image (PNG) is downloaded in a directory called 'images' placed in the controllers directory.
screenshots.controller.js:
const path = require('path');
const axios = require('axios');
const fs = require('fs');
const downloadScreenshot = async(screenshotPath) => {
let isDownloaded = false;
const fileUrl = `https://myexternalapi.com/screenshot/${screenshotPath}`;
const fileName = screenshotPath.split('/')[1]
const downloadFolder = './images'
if(!fs.existsSync(downloadFolder)){
fs.mkdirSync(downloadFolder);
console.log('Images directory created successfully.');
}
const localFilePath = path.resolve(__dirname, downloadFolder, fileName);
try {
const response = await axios({
method: 'GET',
url: fileUrl,
responseType: 'stream',
});
if(response.status === 200){
isDownloaded = true;
}
await response.data.pipe(fs.createWriteStream(localFilePath));
} catch (error) {
console.log('Error occured while downloading screenshot... : ', error);
}
return { isDownloaded, fileName };
}
const readScreenshot = async(req, res) => {
try {
const {isDownloaded, fileName} = await downloadScreenshot(req.body.temp);
if(isDownloaded){
console.log('__dirname + /images/ + fileName : ', __dirname + '/images/' + fileName )
res
.status(200)
.sendFile(fileName, {root : __dirname + '/images/'} );
} else {
res
.status(500)
.send({
message: 'No screenshot for this offer...'
})
}
} catch (error) {
console.log('Error occured while retrieving screenshot...', error)
res
.status(500)
.send({ message: error });
}
}
module.exports = {
readScreenshot: readScreenshot,
}
I would like to display the required image in my Vue app. Thus, I created the following view: ReadScreenshot.vue
<template>
<div>
<img :src="img">
</div>
</template>
<script>
import Screenshots from '../../services/screenshots.service'
export default {
props: ['id'],
data(){
return {
img: '',
}
},
async mounted(){
console.log(this.id)
const temp = await Screenshots.readScreenshot({ temp: this.id });
console.log(temp)
this.img = temp.data
}
}
</script>
Here is my screenshots.service.js script:
import api from '../../http-common';
export default new class ScreenshotsService {
//Read Screenshot
readScreenshot(screenshotName){
return api.post('read/screenshot', screenshotName)
}
}
Console.log(temp) is returning empty data.
In the screenshots.controller.js file, if I'm forcing the fileName with an existing one in the sendFile function, e.g. '2882LsgIXHOiXiOQ5MSv3R6v1hDijAdG5i756CdG5o7v527i5sS1XZgiXR6i1sSGj.png', I'm receiving a non empty data in my ReadScreenshot.vue .
Even if I'm receiving the data, the image is still not displayed...
How should I proceed, to get this right?
thks for your help

Related

"Unexpected end of form" post man error while using multer middleware Node js

back-end:
import multer from "multer";
const upload = multer({ dest: "upload" });
router.route("/register").post(upload.single("file"), register);`
front-end:
const signUpHandler = async (e) => {
e.preventDefault();
const myForm = new FormData();
myForm.append("name", name);
myForm.append("email", email);
myForm.append("password", password);
myForm.append("file", file);
if (!check) {
alert("Enter all the fields carefully!");
} else {
try {
dispatch(setLoading(true));
const { data } = await axios.post(
`${url}/register`,
myForm,
{
headers: {
"Content-Type": `multipart/form-data; `,
},
}
);
} catch (e) {
console.log(e);
}
}
};
I was expecting a file in req.file in the register function after the multer middleware but whenever I am sending a request to the URL postman is giving me the same error.

node js express file upload is corrupted

Uploaded files are the same size 16 bytes and corrupted. What am I doing wrong?
looks like the server code is working as it should, most likely a client side issue. But I could be wrong, so I added everything.
server side code:
import path from 'path'
import fs from 'fs'
import { fileURLToPath } from 'url'
class authController {
downloadFile(req, res) {
console.log(req.query)
try {
const parentFolder = req.query.parentFolder
const folderId = req.query.folderId
const fileName = req.query.fileName
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const file = path.join(__dirname, `../files/${parentFolder}/${folderId}/${fileName}`)
res.download(file, fileName)
} catch (e) {
console.log(e)
res.status(500).json({ message: 'Something went wrong, please try again' })
}
}
}
export default new authController()
client side code:
onClick={async function (e) {
e.stopPropagation()
const request = 'downloadFile'
const response = await fetch(`/api/auth/${request}?parentFolder=${parentFolder}&folderId=${folderId}&fileName=${item}`, {
headers: {
Authorization: 'Bearer ' + auth.token,
},
})
if (response.status === 200) {
console.log(response)
const blob = response.blob()
const downloadUrl = window.URL.createObjectURL(new Blob([blob], { type: 'image/png' }))
const link = document.createElement('a')
link.href = downloadUrl
link.download = item
document.body.appendChild(link)
link.click()
link.remove()
}
}}
I managed to solve the problem. Replaced
const blob = response.blob()
with const blob = await response.blob() and everything worked.

MERN Stack - Download file from Amazon s3 using #aws-sdk/client-s3 & #aws-sdk/s3-request-presigner

I am trying to download an image from Amazon s3 using the #aws-sdk/client-s3 package. The image will download but I can't open it. I get an error and says it is an unrecognizable format.
React Component Download Function
const downloadImg = (e) => {
const href = e.target.getAttribute('img-data');
var img = href.split('/').pop();
const options = {
method: 'GET',
headers: { "Authorization" : `Bearer ${token}` },
};
fetch(`/download-img/${img}`, options)
.then(response => response.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = img;
document.body.appendChild(a);
a.click();
a.remove();
});
}
Node/Express Route
// #desc Download Screenshot
// #route get /download-img
// #access Private
app.get('/download-img/:id', authenticateToken, async(req, res) => {
const imgUrl = req.params.id;
try {
const getObjectParams = {
Bucket: awsBucketName,
Key: imgUrl,
}
const command = new GetObjectCommand(getObjectParams);
const file = await getSignedUrl(s3, command, {expiresIn: 60});
const img = axios.get(file)
.then(function (response) {
res.send(response.data)
})
.catch(function (error) {
// handle error
console.log(error);
})
} catch (err) {
console.log(err)
}
});
Response.data Output

How can I upload an image and form data as well on a single button click?

I am making a practice project in MERN stack and wanted to upload images from react js with the form on single button click, so I needed to call two apis on just one button click. But I am having errors that's why I am unable to upload image and form data as well.
My react js code here:
const URL = "http://localhost:2040/add_recipe";
const formData = new FormData();
formData.append("recipe_image", selectedFile);
let config = {
headers: {
"Content-Type": "multipart/form-data",
authorization: JSON.parse(localStorage.getItem("token")),
},
};
axios
.post(URL, formData, config)
.then((response) => {
console.log("Image uploaded successfully" + response);
})
.catch((error) => {
console.log("Error while uploading image" + error);
});
and here is my backend api:
const Recipe = require("../models/Recipe");
const fs = require("fs");
let filePath = "";
const AddRecipe = async (req, res) => {
if (req.file) {
filePath = req.file.path;
}
console.log("filepath: " + filePath);
let recipee = await Recipe.findOne({ name: req.body.name });
if (recipee) {
res.json({ Response: "Recipe already exists!" });
} else {
if (
req.body.category &&
req.body.ptime &&
req.body.name &&
req.body.noOfPeople &&
req.body.shortDesc &&
req.body.recipe
) {
let recipe = await Recipe.create({
category: req.body.category,
ptime: req.body.ptime,
name: req.body.name,
noOfPeople: req.body.noOfPeople,
shortDesc: req.body.shortDesc,
recipe: req.body.recipe,
avatar: {
data: fs.readFileSync(filePath),
contentType: "image/png",
},
});
let result = await recipe;
console.log(filePath + " .......path");
if (result.name) {
res.json({ Response: "Recipe added successfully!" });
} else {
res.json({ Response: "Recipe not added!" });
}
}
}
};
module.exports = { AddRecipe };
This is how I called the api with multer already setup
app.post("/add_recipe", verifyToken, upload.single("recipe_image"), AddRecipe);
I found the answer, actually I had to sent all data using FormData inside the axios request and its content-type would be multipart/form-data.
So, the request should be one because url is same and we can send form data and image as well using FormData append method and on backend we can get image as req.file and data as req.body.*
That's all!

multer, react-native image upload not working

I am trying to upload a picture with an image picker. I made an image component and make an image-picker fill the component, but uploading the image data to the server doesn't work.
this is the code that is called by onPress attached to a button:
const handlePhoto = async () =>{
if(image!== null){
console.log(image)
const fileToUpload = image;
const data = new FormData();
data.append('name', 'Image Upload');
data.append('file', fileToUpload);
let res = await fetch(
'http://localhost:3000/user/pic_upload',
{
method: 'post',
body: data,
headers: {
'Content-Type': 'multipart/form-data; ',
},
}
);
let responseJson = await res.json();
console.log(responseJson,'result')
if (responseJson.status == 1) {
alert('Upload Successful');
}
} else {
alert('Please Select File first');
}
}
and at index file for user router:
const upload=multer({
storage:multer.diskStorage({
destination:function(req,file,callback){
callback(null,'uploads/')
},
filename:function(req,file,callback){
callback(null,new Date().valueOf()+path.extname(file.originalname))
}
}),
});
router.post('/pic_upload', upload.single('file'), controller.picUpload)
and picUpload router just has console.log
What should I fix to make it work?

Resources