Problem with request in react and express.js - reactjs

so when i send a request which looks like that:
everythig in this api:
router.post('', async (req, res) => {
try {
if(!req.files || !req.body.format) {
res.send({
status: false,
message: 'No file or format'
});
} else {
let uuidv4 = () =>{
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
let video = req.files.video;
let video_name = uuidv4()
let video_format = req.body.format
if (allowedFormats.includes(video_format)) {
let oldVideoPath = './public/uploads/' + video_name + "." + video_format
const newVideoPath = './public/converted/' + video_name + ".mp3"
let video_path = oldVideoPath
video.mv(oldVideoPath)
let proc = new ffmpeg({source: video_path, nolog: true})
proc.setFfmpegPath("./ffmpeg/bin/ffmpeg.exe")
proc
.toFormat('mp3')
.on('end', function () {
res.send({
status: true,
message: 'File has been uploaded',
file: newVideoPath.substring(1)
});
})
.on('error', function (err) {
res.send({
status: false,
message: 'An error occurred ' + err,
});
})
.saveToFile(newVideoPath)
} else {
res.send({
status: false,
message: 'Wrong format!',
})
}
}
} catch (err) {
res.status(500).send(err);
}
});
works perfectly, but the second i send it from react
const fileHandler = (file) => {
const data = new FormData()
data.append('file', file)
data.append('format', baseFormat)
fetch(process.env.REACT_APP_API_IP+'/upload-video', {
method: 'POST',
body: data
})
.then(response => response.json())
.then(data => console.log(data))
}
it gives me an 500 (Internal Server Error).
I checked and when sent from react the file and format reach the api but it breaks somewhere after the uuidv4 function.
Any help appreciated!

You should specify that it is form data.
Add to your fetch
headers: { 'Content-Type': 'multipart/form-data' },
Other issue is that express does not handle multipart/form-data by itself. You have to use some middleware like multer - https://github.com/expressjs/multer
Express part:
const multer = require('multer');
const upload = multer({ dest: "uploads/" });
app.post("/upload-video", upload.single("video"), (req, res) => {
let video = req.file
// rest of your code
}
And in you react code remember to use video field name:
const fileHandler = (file) => {
const data = new FormData()
data.append('video', file)
// ...

Related

how can i save contentype/mimetype of a file/image to node.js using expess and multer

Still a beginner, I was currently learning how to upload images, save them to a database and then display them to a client, in the database, i m trying to save the filename, contentType and base64 Encoding, all with the type String, but i keep getting the error: error "uploads validation failed: ContentType: Path ContentType is required."
But I did specify the path, can anyone please help. find code below
schema.js
const mongoose = require('mongoose')
const uploadSchema = new mongoose.Schema({
filename: {
type: String,
unique: true,
required: true
},
ContentType: {
type: String,
required: true
},
imageBase64: {
type: String,
required: true
}
})
module.exports = mongoose.model('uploads', uploadSchema)
controller.js
const UploadModel = require('../model/schema')
const fs = require('fs')
const mongoose = require('mongoose')
exports.home = (req, res, next) => {
res.render('index')
}
exports.uploads = (req, res, next) => {
const files = req.files
if (!files) {
const err = new Error('Please choose files')
err.httpStatusCode = 400
return next(err)
}
// Convert images into based64 encoding
let imgArray = files.map((file) => {
let img = fs.readFileSync(file.path)
return encode_image = img.toString('base64')
})
let results = imgArray.map((src, index) => {
// Create object to store data in the collection
let finalImg = {
filename: files[index].originalname,
contentType: files[index].mimetype,
imageBase64: src
}
console.log(finalImg.contentType)
let newUpload = new UploadModel(finalImg)
return newUpload
.save()
.then(() => {
return {msg: `${files[index].originalname} Uploaded Sucessfully...!`}
})
.catch((err) => {
if(err) {
if(err.name === 'MongoError' && err.code === 11000) {
return Promise.reject({err: `Duplicate ${files[index].originalname}.File Already exists!`})
}
return Promise.reject({error: err.message || `Cannot Upload ${files[index].originalname} Something missing!`})
}
})
})
Promise.all(results)
.then(msg => {
//res.redirect('/')
res.json(msg)
})
.catch(err => {
res.json(err)
})
}

sending multiple base64 images to cloudinary using node and getting error -4064, code: 'ENAMETOOLONG'

I am getting my base64 urls and they are correct because if I send only one image its uploaded correctly to cloudinary but when sending multiple images Ii get an error 'ENAMETOOLONG' with error number 4064
here is my graphql resolver
createEvent: async (args: any, req: any) => {
if (!req.isAuth) {
throw new Error("Unauthenticated!!!!");
}
let imagesArr: any[] = [];
for (let i = 0; i < args.eventInput.images.length; i++) {
const result = await cloudinary.uploader.upload(
args.eventInput.images[i],
{
public_id: `${args.eventInput.title}${new Date(
args.eventInput.date
)}${i}`,
folder: "Eventers",
allowedFormats: ["jpeg", "png", "jpg"],
}
);
console.log(result.url, result.public_id);
imagesArr.push({ public_id: result.public_id, url: result.secure_url });
}
const event = new Event({
title: args.eventInput.title,
description: args.eventInput.description,
price: +args.eventInput.price,
date: new Date(args.eventInput.date),
category: args.eventInput.category,
brief: args.eventInput.brief,
tickets: +args.eventInput.tickets,
images: [...imagesArr],
author: req.userId,
});
let createdEvent;
try {
const result = await event.save();
createdEvent = transformEvent(result);
const author = await User.findById(req.userId);
if (!author) {
throw new Error("User not found.");
}
author.createdEvents.push(event);
await author.save();
return createdEvent;
} catch (error) {
console.log(error);
throw error;
}
},
here is the response i get when trying to submit multiple base64 urls
message: "Unexpected error value: { error: { errno: -4064, code: \"ENAMETOOLONG\", syscall: \"open\", path: \"C:\\\\Users\\\\user\\\\Desktop\\\\graphQl maximillian yt course\\\\bookingEvents\\\\backend\\\\data:image\\\\jpeg;base64,\\\\9j\\\\4AAQSkZJRgABAQAAAQABAAD\\\\2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj\\\\2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj\\\\wAARCAQIAkUDASIAAhEBAxEB\\\\8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL\\\\8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6\\\\8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL\\\\8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uP…"
and here is how i transform the images to base
const fileOnChangeHandler = async (e: ChangeEvent<HTMLInputElement>) => {
let files = Array.from(e.target.files!);
files.forEach((file: any) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = async () => {
setImageLinks((prevArr: any) => [...prevArr, reader.result]);
};
});
};
and here is how i send the data to the back end
export const fetchAsyncCreateEvents = createAsyncThunk(
"Events/fetchAsyncCreateEvents",
async (eventInput: Event) => {
const {
title,
category,
description,
brief,
price,
date,
tickets,
images,
} = eventInput;
const { data } = await axios.post<Event>(
API,
{
query: `
mutation{
createEvent(eventInput:{title:"${title}",category:"${category}",description:"""${description}""",brief:"${brief}",price:${price},date:"${date}",tickets:${tickets},images:"${images}"}){
author{
email
}
}
}
`,
},
{
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + localStorage.getItem("token"),
},
}
);
return data;
}
);
I've tried alot of things like adding .replace(/(\r\n|\n|\r)/gm,"") to the for loop at each image array index but it didnt work
and here is one of the base 64 urls
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAQIAkUDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4"
I deleted more than half of the url so I could submit the question.
i solved the problem it was so simple the problem is i am sending the array of images base64 in a wrong way in graphql mutation
i was sending it with a quotation wrapping it and it turned out you have to use quotations only for strings and for arrays you should json.stringify
export const fetchAsyncCreateEvents = createAsyncThunk(
"Events/fetchAsyncCreateEvents",
async (eventInput: Event) => {
const {
title,
category,
description,
brief,
price,
date,
tickets,
images,
} = eventInput;
const { data } = await axios.post<Event>(
API,
{
query: `
mutation{
createEvent(eventInput:{title:"${title}",category:"${category}",description:"""${description}""",brief:"${brief}",price:${price},date:"${date}",tickets:${tickets},images:${JSON.stringify(images)}}){
author{
email
}
}
}
`,
},
{
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + localStorage.getItem("token"),
},
}
);
return data;
}
);

ReactJS axios post: returns null when it comes/goes from/to backend

I am stuck on this problem for 2 days. I am sending POSTrequest from frontend to the backend (and other GET requests too but the problem is only with POST). However, when my data goes to the backend it does not post anything to the rest api even though response is 200 OK. That's why when in response it should have given the posted data, it can't find it and gives null. This is my POST code in backend index.js:
const { response, request } = require('express');
require('dotenv').config()
const express = require('express');
const morgan = require('morgan');
const Contact = require('./models/contact.cjs');
const cors = require('cors')
const app = express();
app.use(express.json())
app.use(express.static('build'))
app.use(cors())
morgan.token('body', req => {
return JSON.stringify(req.body)
})
app.use(morgan(':method :url :status :res[content-length] - :response-time ms :body'));
const generateId = () => {
const randNum = Math.floor(Math.random() * 5000)
return randNum;
}
app.post('/api/persons', (req, res) => {
const body = req.body
console.log(body)
if (!body.name || !body.number) {
return res.status(400).json({
error: "missing data"
})
} else if (Contact.find({name: body.name})) {
Contact.findOneAndUpdate({name: body.name}, {$set: {number: body.number}}, {new:true})
.then(updatedContacts =>
res.json(updatedContacts)
)
.catch(err => console.log(err))
} else {
const contact = Contact({
id: generateId(),
name: body.name,
number: body.number,
date: new Date()
})
contact.save()
.then(savedContact => {
console.log(savedContact)
res.json(savedContact)
})
.catch(err => {
console.log(err)
})
}
})
const PORT = process.env.PORT
app.listen(PORT, () => {
console.log(`Server is working on ${PORT}`)
})
and this is how my frontend sends data to backend: contacts.js:
const create = (newObject) => {
const readyToPost = {
method: 'post',
url: `${baseUrl}`,
data: newObject,
headers: {'Content-Type': 'application/json'},
json: true
}
const request = axios(readyToPost)
return request.then(response => {
console.log(response.data)
return response.data
})
.catch(err => {
console.log(err)
})
}
And this is my react app's frontend.
Any ideas about why my data becomes null?
Any help would be appreciated!
Due to the synchronous nature of your code, the condition Contact.find({name: body.name}) was always returning the Query object which is true due to which the else if block was getting executed even when there was no such document. After entering the else if block, since there was no match, so findOneAndUpdate() was returning null.
Use findOne() instead of find(). find() returns a cursor which is empty but true whereas findOne() returns the first document matched (if matched) or else it will return null (if not matched).
// index.js (Backend)
app.post("/api/persons", async (req, res) => {
const body = req.body;
if (!body.name || !body.number) {
return res.status(400).json({
error: "missing data",
});
}
// Using findOne() instead of find(). Returns null if record not found.
const existing = await Contact.findOne({ name: body.name });
if (existing) {
Contact.findOneAndUpdate(
{ name: body.name },
{ $set: { number: body.number } },
{ new: true }
)
.then((updatedContacts) => {
console.log(updatedContacts);
res.status(200).json(updatedContacts);
})
.catch((err) => console.log(err));
} else {
const contact = Contact({
id: generateId(),
name: body.name,
number: body.number,
date: new Date(),
});
contact
.save()
.then((savedContact) => {
console.log(savedContact);
res.status(201).json(savedContact);
})
.catch((err) => {
console.log(err);
});
}
});

How do I upload a base64 image to firebase using Busboy (React)?

I am having trouble uploading an image to the db after cropping. I am able to upload the file on Postman, but can't figure out how to do it after cropping and getting it returned as a base64.
Here is my route that works with uploading a raw file, but not the base64:
exports.uploadProfileMedia = (req, res) => {
const BusBoy = require("busboy")
const path = require("path")
const os = require("os")
const fs = require("fs")
let mediaFileName
let mediaToBeUploaded = {}
let generatedToken = uuidv4()
const busboy = new BusBoy({ headers: req.headers })
busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
console.log(file, "before")
if (
mimetype !== "image/jpeg" &&
mimetype !== "image/png" &&
mimetype !== "image/heic"
) {
return res.status(400).json({ error: "Wrong file type submitted" })
}
const mediaExtension = filename.split(".")[
filename.split(".").length - 1
]
mediaFileName = `${Math.round(
Math.random() * 100000000000
).toString()}.${mediaExtension}`
const filepath = path.join(os.tmpdir(), mediaFileName)
mediaToBeUploaded = { filepath, mimetype }
file.pipe(fs.createWriteStream(filepath))
console.log(file, "after")
})
busboy.on("finish", () => {
admin
.storage()
.bucket()
.upload(mediaToBeUploaded.filepath, {
resumable: false,
metadata: {
metadata: {
contentType: mediaToBeUploaded.mimetype,
firebaseStorageDownloadTokens: generatedToken
}
}
})
.then(() => {
const mediaUrl = `https://firebasestorage.googleapis.com/v0/b/${firebaseConfig.storageBucket}/o/${mediaFileName}?alt=media&token=${generatedToken}`
return db
.doc(`/users/${req.user.username}`)
.update({ mediaUrl })
})
.then(() => {
return res
.status(201)
.json({ message: "Media uploaded successfully" })
})
.catch((err) => {
console.error(err)
return res.status(500).json({ error: err.code })
})
})
busboy.end(req.rawBody)
}
Here is where I pass in a base64 after cropping:
const uploadProfileMedia = (formData) => {
axios.defaults.headers.common["Authorization"] = localStorage.getItem(
"FBIdToken"
)
axios
.post("/api/user/media", formData)
.then((res) => {})
.catch((err) => console.log(err))
console.log(formData, "form")
}
Here is a snippet of the above console.log():
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDREN
Here is the function which calls the uploadProfileMedia():
const showCroppedImage = useCallback(async () => {
console.log(imageSrc, "imgsrc")
try {
const croppedImage = await getCroppedImg(
imageSrc,
croppedAreaPixels
)
setCroppedImage(croppedImage)
uploadProfileMedia(croppedImage)
console.log(croppedImage, "showcroppedImage")
} catch (e) {
console.error(e)
}
}, [imageSrc, croppedAreaPixels])

501 Not Implemented error in small web app

I am trying to upload images to an S3 bucket with react and expressjs. When I attempt to upload the image I get a 501 Not Implemented Error. I am using axios to contact the end point I created in the server code.
My react code:
class FileUpload extends Component {
state = {
file: null
};
submitFile = (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('file', this.state.file[0]);
axios.post(`test-upload`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(response => {
// handle your response;
}).catch(error => {
// handle your error
});
}
handleFileUpload = (event) => {
this.setState({file: event.target.files});
}
render () {
return (
<form onSubmit={this.submitFile}>
<input label='upload file' type='file' onChange=
{this.handleFileUpload} />
<button type='submit'>Send</button>
</form>
);
}
}
export default FileUpload;
My server code:
const uploadFile = (buffer, name, type) => {
const params = {
ACL: 'public-read',
Body: buffer,
Bucket: process.env.S3_BUCKET,
ContentType: type.mime,
Key: `${name}.${type.ext}`
};
return s3.upload(params).promise();
};
app.use('/', (req,res) =>{
res.send(JSON.stringify({ greeting: `Hello!` }));
});
// Define POST route
app.post('/test-upload', (request, response) => {
const form = new multiparty.Form();
form.parse(request, async (error, fields, files) => {
if (error) throw new Error(error);
try {
const path = files.file[0].path;
const buffer = fs.readFileSync(path);
const type = fileType(buffer);
const timestamp = Date.now().toString();
const fileName = `bucketFolder/${timestamp}-lg`;
const data = await uploadFile(buffer, fileName, type);
return response.status(200).send(data);
} catch (error) {
return response.status(400).send(error);
}
});
});
This was done by following a guide on the internet but there seems to be something missing that I just can't figure out.
Figured it out in the end,
axios.post(/test-upload,
should have been
axios.post(http://localhost:3000/test-upload,

Resources