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,
Related
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;
}
);
I'm using react js version 17, I want to upload file and send it to my node js api.
I have two buttons, The first button used to read the first line in the file,
the second button is for the call to the back end server to save the file in the database as a file
I have create a formData to set my formData file input always i got empty object.
Here's my code :
const [myFile,setMyFile] = useState();
const [headers,setHeaders] = useState();
const readFile = e =>{
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function(e) {
const text = e.target.result;
const headers = text.slice(0,text.indexOf('\n')).split(';');
setHeaders(headers)
}
reader.readAsText(file);
setMyFile(file)
}
const callApi = e => {
const formData = new FormData();
formData.append(
"file",
myFile,
);
axios.post('localhost:8080/uploadFile', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
My formData always return an empty object {}
Upload logic in react js to send csv in API to backend :
import React, { Component } from "react";
import axios from 'axios';
import AppContext from './AppContext';
const SERVER_URL = process.env.REACT_APP_SERVER_URL;
const PROTOCOL = process.env.REACT_APP_PROTOCOL;
const PORT = process.env.REACT_APP_PORT;
class UploadMeasure extends Component {
constructor() {
super();
this.state = {
csvfile: undefined
};
this.updateData = this.updateData.bind(this);
}
handleChange = event => {
this.setState({
csvfile: event.target.files[0]
});
};
importCSV = () => {
const { csvfile } = this.state;
console.log(csvfile);
var fileName = csvfile.name;
const formData = new FormData();
formData.append(
"fileChooser",
csvfile,
);
axios.post(PROTOCOL + "://" + SERVER_URL + ":" + PORT + "/uploadMeasures/" + AppContext.username + "?&fileName=" + fileName, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => { // then print response status
console.log(res)
if (res === 'success') {
alert("File data uploaded Successfully");
} else {
if (res === 'Error') {
alert("Please ensure that your CSV file is formatted using the correct template, if you have any doubt contact the support team.");
} else {
console.log(res)
}
}
})
};
updateData(result) {
var data = result.data;
console.log(data);
}
render() {
console.log(this.state.csvfile);
return (
<div className="App">
<h2>Import CSV File!</h2>
<input
className="csv-input"
type="file"
ref={input => {
this.filesInput = input;
}}
name="file"
placeholder={null}
onChange={this.handleChange}
/>
<p />
<button onClick={this.importCSV}> Upload now!</button>
</div>
);
}
}
export default UploadMeasure;
I would like to download a stream file in my project.
Indeed the response form the API is like a blob.
Here i leave my code;
id and filterBody arrives as props to my component.
Really i confused if some where there are mistakes or No?
Can any one help me to find my mistakes?
Thank you.
const fetchBlobFile = async (setBlobFile, id, filterBody) => {
try {
let response = await get(`http://localhost:4000/error/table/export?error_id=${id}`, filterBody)
setBlobFile(response?.data?.blob())
} catch (error) {
}
}
function exportXslFile ({id, filterBody}) {
const [blobFile, setBlobFile] = useState(null)
useEffect(() => {
fetchBlobFile(setBlobFile, id, filterBody)
}, [id])
const export = () => {
const url = window.URL.createObjectURL(blobFile);
window.location = url
}
return (
<button className="export" onClick={export}><ExportXslFile /> Export</button>
)
}
I solved the problem as following.
This code completely works; but only be careful to import necessary packages.
const fetchBlobFile = async (setBlobFileLoading, id, body) => {
try {
const a = document.createElement("a");
a.style.display = "none";
document.body.appendChild(a);
setBlobFileLoading(true);
var data = JSON.stringify(body);
var config = {
method: 'post',
url: `http://localhost:4000/table/export?errorCsv_id=${id}`,
headers: {
'Content-Type': 'application/json'
},
data: data
};
let response = await axios(config);
setBlobFileLoading(false)
const blobFile = new Blob([response?.data], { type: 'text/csv' });
const url = window.URL.createObjectURL(blobFile);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
} catch (error) {
}
}
function exportXslFile ({id, body}) {
const [blobFileLoading, setBlobFileLoading] = useState(false)
const export = () => {
fetchBlobFile(setBlobFileLoading, id, filterBody)
}
return (
{blobFileLoading && <div className="loading fixed"><Loader /></div>} // set up loader
<button className="export" onClick={export}>Export</button>
) //download button
}
Multer worked fine when I upload multiple images by using Postman but when I try to send files as an array from the front-end, it always return files is undefined and files is not iterable.
I think the problem is in the front-end React. How to fix this problem?
Back-end
router.post('/multer',auth ,upload.array('image'), async (req, res) => { //NOTE image is the field name
try {
const urls = []
const files = req.files;
console.log('Upload cloudinary running '+ files)
.
.
.
Front-end React
import React, {Fragment, useState, useEffect} from 'react';
const Dashboard = ({auth: { user, loading }}) => {
.
.
.
const [files, setFiles] = useState([]);
const handleChange = e => {
const file_reader = new FileReader();
const file = e.target.files[0];
let file = e.target.files[0];
file_reader.onload = () => {
setFiles([...files, { image: file_reader.result }]);
};
file_reader.readAsDataURL(file);
}
const handleSubbmitFile = (e) => {
e.preventDefault();
if(!files) return;
uploadImage(files);
}
const uploadImage = async (base64EncodedImage) => {
try {
const config = {
headers:{
'Content-Type' : 'application/json'
}
}
const body = JSON.stringify({files: base64EncodedImage});
await axios.post('/api/blogs/multer', body, config);
} catch (error) {
console.log(error);
}
}
return(
<form onSubmit={handleSubbmitFile} className="form-outline">
<input name="image" onChange={handleChange} type="file"
class="form-control-file" id="exampleFormControlFile1"
accept="image/*"/>
</form>
)
}
I found the problems and I fixed it by using formData in handleSubbmitFile and set the property filed to image by using append.
const handleSubbmitFile = (e) => {
e.preventDefault(); //NOTE prevent from reload the page
let formData = new FormData();
for(var i = 0 ; i < files.length; i++){
formData.append('image',files[i])
}
if(!files) return;
uploadImage(formData);
}
Another problems is that using Json.stringify() before using axios.
I didn't use Json.stringify() to convert formData before sending it to back-end via axios. As a result, Multer work well without problems
const uploadImage = async (formData) => {
try {
const config = {
headers:{
'Content-Type' : 'application/json'
}
}
await axios.post('/api/blogs/multer', formData, config);
} catch (error) {
console.log(error);
}
}
Basically I want to record audio and I'm using react-mic for this but it gives back blob but I want mp3 or wav file to send to the backend. How to POST blob file to the server?
This is my code in App.js
import React from "react";
import { ReactMic } from "react-mic";
import $ from "jquery";
import { findDOMNode } from "react-dom";
import "./App.css";
class App extends React.Component {
handleDisplayForStart = () => {
const startBtn = findDOMNode(this.refs.startBtn);
$(startBtn).addClass("d-none");
const stopBtn = findDOMNode(this.refs.stopBtn);
$(stopBtn).removeClass("d-none");
};
handleDisplayForStop = () => {
const stopBtn = findDOMNode(this.refs.stopBtn);
$(stopBtn).addClass("d-none");
const processBtn = findDOMNode(this.refs.processBtn);
$(processBtn).removeClass("d-none");
};
constructor(props) {
super(props);
this.state = {
blobURL: null,
recordedBlob: null,
record: false,
};
}
startRecording = () => {
this.setState({ record: true });
this.handleDisplayForStart();
};
stopRecording = () => {
this.setState({ record: false });
this.handleDisplayForStop();
};
onData(recordedBlob) {
console.log("chunk of real-time data is: ", recordedBlob);
}
onStop = (recordedBlob) => {
console.log(recordedBlob.blobURL);
const blobURL = recordedBlob.blobURL;
this.setState({ blobURL: blobURL });
this.onUpload();
return recordedBlob.blobURL;
};
onUpload = (recordedBlob) => {
// var form = new FormData();
// form.append("file", recordedBlob);
// fetch("http://localhost:3000/audio", {
// // content-type header should not be specified!
// method: "POST",
// body: form,
// })
// .then(function (response) {
// return response.text();
// })
// .then(function (text) {
// console.log(text); // The text the endpoint returns
// })
// .catch((error) => console.log(error));
};
render() {
return (
<div className="App">
<ReactMic
visualSetting="frequencyBars"
// mimeType='audio/mp3'
record={this.state.record}
className="d-none"
onStop={this.onStop}
onData={this.onData}
/>
<button
ref="startBtn"
className="start-btn"
onClick={this.startRecording}
type="button"
>
START
</button>
<button
ref="stopBtn"
className="stop-btn concentric-circles d-none"
onClick={this.stopRecording}
type="button"
>
STOP
</button>
<button
ref="processBtn"
className="process-btn d-none"
onClick={this.onUpload}
>
Processing..
</button>
<br />
<audio src={this.state.blobURL} controls />
</div>
);
}
}
export default App;
I tried various things from medium blogs and different StackOverflow answers but anything doesn't work correctly.
This may be a bit late, i also came across this problem and i also couldn't find a solution, sharing the solution so it may help others.
code for sending recorded blob file using react-mic to server,
const onStop = (blob) => {
const formData = new FormData();
// if you print blob in console you may get details of this obj
let blobWithProp = new Blob([blob["blob"]], blob["options"]);
formData.append("file", blobWithProp);
const postRequest = {
method: "POST",
body: formData,
};
fetch("http://127.0.0.1:5000/audio_out/", postRequest)
.then(async (res) => {
const data = await res.json();
console.log(data);
if (!res.ok) {
const err = (data && data.message) || res.status;
return Promise.reject(err);
}
})
.catch((err) => {
console.log(err);
});
};
Here onStop() is the callback function which is executed when recording stopped.
On your commented part of your code you are sending recorded blob file directly. I don't know much about it, but if you log the received file on console you may see it is an object file containing blob, options, etc. So, I think we need to create a new Blob file from that. I am just a beginner in web development, may be i am wrong. But the above code solved the problem.