How to access image from uploaded on nestjs server - node.js

I have a nestjs server and I have uploaded the images but when I try to access to those images they are a bunch of stuff that cant be interpreted as an image.(I also tried converting them to blob which then I converted to objectURL and then set it as src for img tag but that didnt work either).Upload code:
#Post('upload')
#UseInterceptors(FileInterceptor('file',{
storage: diskStorage({
destination: './uploads',
filename: editFileName,
}),
fileFilter: imageFileFilter,
}))
uploadFile(#UploadedFile() file){
console.log(file);
file.filename = file.originalname;
const response = {
originalname: file.originalname,
filename: file.filename,
}
return response;
}
The above upload code perfectly saves the image as index-53a2.jpg in my uploads folder. Now trying to get the image using get req by:
#Get()
display(#Res() res){
res.sendFile('index-53a2.jpg',{ root: './uploads' })
}
logging response for this it gives some string of unreadable(probably encoded) stuff.
code I used for testing:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script>
$(function () {
$('#abc').on('submit', function (e) {
e.preventDefault();
$.ajax({
url: 'http:/localhost:3000/student/upload',
method:'POST',
data: new FormData(this),
contentType: false,
cache:false,
processData:false,
success: function (data) {
console.log(data);
// location.reload();
}
});
});
});
function fun(){
$.ajax({
url: 'http://localhost:3000/student',
success: function(data){
console.log('s',data);
let blob = new Blob([data]);
var objectURL = URL.createObjectURL(blob);
document.getElementById('img').src = objectURL;
},
error: function(data){
console.log('e',data);
}
})
}
</script>
</head>
<body>
<img alt="Image" id="img">
<form enctype= "multipart/form-data" id="abc">
<input type="file" name="file" required accept="image/*"><br>
<input name="submit" type="submit" value="Submit">
</form>
<button onclick="fun()">Button</button>
</body>
</html>
Also this html code is just for testing, my main purpose is to use this server so that I can take student image and data(contains basic details like name, phone, etc.) from angular and save it on mongoDB. Also I dont have any idea how to send my image from angular to nestjs and how to save it(and where to save it on MongoDB or Nestjs server and how)
Any help would be greatly appreciated!!!
Thanks in advance.

To access to your files with NestJs you need to define your static assets directory name in the main.ts using the .useStaticAssets method on your app
app.useStaticAssets(join(__dirname, '..', 'public'), {
index: false,
prefix: '/public',
});

I found solution to this. So what we have to do is basically append all our data in formData and send it in the request from angular.
let formData = new FormData();
formData.append('image',this.image);
Now this image attribute is taken from the function triggered by the onchange on the input tag that takes image as input.
onChange(event){
this.image = event.target.files[0];
}
Now we send it to backend from our service.
sendReq(formData){
this.http.post('localhost:3000/your_route',formData);
}
Now while accessing it from the Nestjs server we use FileInterceptor.
import { Controller, Get, Post, Res, UploadedFile, UseInterceptors, Body } from '#nestjs/common';
import { FileInterceptor } from '#nestjs/platform-express';
import { editFileName, imageFileFilter } from './funcs';
import { diskStorage } from 'multer';
#Post('your_route')
#UseInterceptors(FileInterceptor('image',{
storage: diskStorage({
destination: './uploads',
filename: editFileName,
}),
fileFilter: imageFileFilter,
}))
async func(#UploadedFile() file, #Body() body){
try{
body.image = file.filename;
body.view = false;
let res = await this.yourService.yourFunc(body);
return {
'success': true,
'data': res
}
}
catch(err){
console.log(err);
return {
'success': false,
'data': err
}
}
}
const imageFileFilter = (req, file, callback) => {
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
return callback(new Error('Only image files are allowed!'), false);
}
callback(null, true);
};
const editFileName = (req, file, callback) => {
const name = file.originalname.split('.')[0];
const fileExtName = '.'+file.originalname.split('.')[1];
const randomName = Array(4)
.fill(null)
.map(() => Math.round(Math.random() * 16).toString(16))
.join('');
callback(null, `${name}-${randomName}${fileExtName}`);
};
So this way we get a uploads folder in our root directory and image uploaded to our server gets saved here. To save the image the name I have user here is the name of the file being uploaded + '-' + a sequence of random char and int of length 4(Here you can have logic of your own).

Related

How to make an API to return JSON text after uploading files with Angular/Node JS?

My goal is to create a File Select interface in order to upload files on a server using Angular CLI and Node JS.
I built an API with Node JS that must check the type of the file (only CSV files) and then return a JSON text saying whether the upload succeeds or fails. I decided to give it a try with Multer (see https://www.npmjs.com/package/multer).
Everything is working and my CSV is well uploaded. But I don't manage to get the JSON message from the API after a user uploads his file.
Here is the files I created :
HTML PART
<div class="file-upload">
<input type="file" name="file" ng2FileSelect [uploader]="uploader" accept="text/csv" />
<button type="button" class="btn btn-primary btn-sm" (click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
RUN
</button>
</div>
TS PART
const URL = 'https://xxxxx.com:xxxx/upload';
export class SelectFileComponent implements OnInit {
public uploader: FileUploader = new FileUploader({
url: URL,
itemAlias: 'fileToUpload',
});
constructor() { }
ngOnInit() {
this.uploader.onAfterAddingFile = (file) => {
file.withCredentials = false;
};
this.uploader.onCompleteItem = (item: any, status: any) => {
};
}
NODE JS PART
// File upload settings
const PATH = './uploads';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, PATH);
},
filename: (req, file, cb) => {
cb(null, file.originalname)
}
});
let upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (file.mimetype == 'application/vnd.ms-excel'){
cb(null, true);
} else {
cb(null, false);
return cb('Only csv format allowed!');
}
}
});
// Post file
app.post('/upload', upload.single('fileToUpload'), async (req, res) => {
// I would like to do :
// if file has not csv extension...
{
return res.json({
success: false,
message: "Bad format, please select a CSV file",
});
}
// else if everything is ok...
{
return res.json({
success: true,
message: "Some success message"
});
}
else {}
});
It seems I can't use a variable created in the "File upload settings" into the "Post file" part.
Have you any ideas to help me to implement that JSON message ?

File upload with react, nodeJS multer doesn't work

i made this function, which takes the file value ( image ) from the file state and send it to upload route, through FormData object
const [file, setFile] = useState(null);
const submitPost = async (e) => {
...
e.preventDefault();
if (file) {
const data = new FormData();
const fileName = `${Date.now()}${file.name}`;
data.append("name", fileName);
data.append("file", file);
try {
await fetch("http://localhost:8000/upload", {
headers: {
"Content-type": "application/json",
},
method: "POST",
body: JSON.stringify(data),
});
// window.location.reload();
} catch (err) {
console.log(err);
}
}
};
the file value in the file state is coming from form file input
<form className="postOptions" onSubmit={submitPost}>
<div className="postAreaBot">
<label htmlFor="file" className="downloadImg">
<AddAPhotoIcon className="postIcon" />
<span>Image</span>
</label>
<input
type="file"
accept=".png,.jpeg,.jpg"
onChange={(e) => setFile(e.target.files[0])}
id="file"
style={{ display: "none" }}
></input>
</div>
<button type="submit">Post</button>
</form>
and then sending the file value to this route for upload on folder images inside folder public using multer and path
app.use("/images", express.static(path.join(__dirname, "public/images")));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "public/images");
},
filename: (req, file, cb) => {
cb(null, req.body.name);
},
});
const upload = multer({ storage });
app.post("/upload", upload.single("file"), (req, res) => {
try {
return res.status(200).json("File uploaded successfully");
} catch (err) {
console.log(err);
}
});
but the image is not being uploaded
what have i tried
i tested the route using file.originalName for postman instead of file.req.body and the route does indeed works and images are being uploaded successfully, i also checked the values name and file in the data object and it appends it successfully, i can't see what is the problem, why it doesn't upload the image file through the react fetch request?
Just remove the JSON.stringify. And change your content type, like the example below:
await fetch("http://localhost:8000/upload", {
headers: {
"Content-type": "multipart/form-data",
},
method: "POST",
body: data,
});

Not getting image file in nodejs after posting from react

I'm sending the image file from react to nodejs. I used the SetImage function where the image file selected by the user is set to the 'myimage' state variable and from handleSubmit I'm posting the images to the '/blog/posts' endpoint using Axios. the image file is getting loaded on the 'myimage' state variable but as I posted using the Axios, I can't see all the data of the image file and giving me the empty object.
This is my React code:-
import React, { useState, useRef } from "react";
import './postblog.css';
import axios from '../axios';
const PostBlog = () => {
const [myimage,setImage] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
axios.post('/blog/posts', {
image:myimage
}).then((res) => {
console.log(res.body);
console.log('successfully posted');
});
}
const SetImage = (e)=>{
console.log(e.target.files[0]);
setImage(e.target.files[0]);
console.log(myimage);
}
return (
<div className="postblog">
<form onSubmit={handleSubmit} enctype="multipart/form-data">
<input type="file" placeholder="Choose your file" onChange={(e)=>{SetImage(e)}} name="myImage"/>
</div>
<button type="submit">Post</button>
</form>
</div>
);
}
export default PostBlog;
This is my Nodejs code:-
var storage = multer.diskStorage({
destination: function(req, res, cb) {
cb(null, './Routers/blog/uploads');
},
filename: function(req, file, cb) {
cb(null, Date.now() + file.originalname);
}
});
var upload = multer({
storage: storage,
limits: {
fieldsize: 1024 * 1024 * 3
}
});
blog.post('/posts', upload.single('myimage'), (req, res, next) => {
console.log(req.body);
console.log(details);
})
The output in the console I'm getting is an empty object
You should send file with content type as multipart/form-data but in your code you are sending file as application/json content type.
...
const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('file', myimage);
const config = {
headers: {
'content-type': 'multipart/form-data'
}
};
axios.post('/blog/posts', formData, config).then((res) => {
console.log(res.body);
console.log('successfully posted');
});
}
...

File Upload from API Routes Next.js not working

I'm trying to upload a file to my server which I'm successfully able to do with my code, but I get a this console output from it:
API resolved without sending a response for /api/upload, this may result in a stalled requests.
The file is successfully put into the folder though.
I don't quite understand how I am not sending a response as to me I am.
What am I doing wrong?
Here is my form code:
const axios = require("axios").default;
class VideoUploadForm extends React.Component {
constructor(props) {
super(props);
this.state = {
file: null,
uploaded: false
};
}
onChangeHandler = event => {
this.setState({
selectedFile: event.target.files[0],
loaded: 0
});
};
onClickHandler = () => {
const data = new FormData();
data.append("video", this.state.selectedFile);
axios
.post("/api/upload", data, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
};
render() {
return (
<div>
<form
action="#"
method="post"
encType="multipart/form-data"
target="transFrame"
>
<input type="file" name="video" onChange={this.onChangeHandler} />
<button onClick={this.onClickHandler}>upload</button>
</form>
<iframe
width="200"
height="100"
name="transFrame"
id="transFrame"
></iframe>
</div>
);
}
}
export default VideoUploadForm;
and the API
import multer from "multer";
export const config = {
api: {
bodyParser: false
}
};
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, "public");
},
filename: function(req, file, cb) {
cb(null, "video.mp4");
}
});
var upload = multer({ storage: storage });
export default async (req, res) => {
upload.single("video")(req, {}, err => {
res.send(req.file.path);
res.end();
console.log(req.file); // do something with the file
});
};
This is where the problem is
res.send(req.file.path);
res.end();
res.send implicitly calls res.write followed by res.end. You should remove the second res.end.
Try
var upload = multer(storage);

Image upload: Node Multer 'LIMIT_UNEXPECTED_FILE' error

I'm trying to use multer to process a profile photp upload on the frontend to the backend but keep getting this error:
{ [Error: Unexpected field]
code: 'LIMIT_UNEXPECTED_FILE',
field: 'file',
storageErrors: [] }
Below is my code:
register.ejs:
<div class="form-group">
<input class="form-control" type="file" name="image" id="image">
</div>
ajax.js:
$('form').submit(function(e) {
e.preventDefault();
var formData = new FormData(this);
// var img = cropper.getCroppedCanvas().toDataURL();
// formData.append('img',img);
$.ajax({
url: '/register',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function () {
console.log('Upload success');
},
error: function () {
console.log('Upload error');
}
});
});
app.js:
var multer = require('multer');
var cloudinary = require('cloudinary');
...
// MULTER
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, "./public/uploads");
},
filename: function(req, file, callback) {
callback(null, Date.now() + file.originalname);
}
});
var upload = multer({ storage : storage}).single("image");
app.post("/register", function(req, res) {
upload(req, res, function(err){
if(err) {
console.log(err);
return res.send("Error uploading file.");
}
res.send("Upload success");
});
});
I also get an undefined object when I try to get req.body.img or req.file. Maybe the formdata is not populated properly? Can anyone shed some light for me?
It says on multer docs that you should pass enctype="multipart/form-data" attribute to your <form> element. I'm not really familiar with ajax, but I think you may have to set contentType: in ajax.js to "multipart/form-data".
I also had a similar error, but it was caused by non-matching text-field keys.
I have also face the same issue, instead of using
var upload = multer({ storage : storage}).single('image');
use the fields() method which allow to handle multiple files at once
app.use(multer({ storage : storage}).fields([{name:'image',maxCount:1}]));
file data store in req.files ,
then you can simply handle the files
that error occur when you try to handle multiple form data object in single multer middleware,
you can use the storage option to store different files in different locations.
further more can go thought official doc

Resources