hi I am using express and multer to receive multiple files in backend from react frontend my react query code is like this:
fileChangeHandler = (event) => {
const data = new FormData()
let files = event.target.files
for (let file of files) {
data.append('file', file)
}
let url = db.url + "/adminendpoint/uploadfile"
axios.post(url, data, {
headers: {
'Content-Type': 'application/json',
Authorization: this.props.token
},
}).then(r => console.log(r.names))
}
the backend data for multer is like this :
uploadFile = async (req,res,next)=>{
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/images')
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' +file.originalname )
}
})
let upload = multer({storage:storage}).array('file')
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
return res.json({err:err})
} else if (err) {
return res.json({err:err})
}
let names=[]
req.files.map(f=> names.push(f.filename))
console.log(names);
res.setHeader('Content-Type', 'application/json');
return res.json({names:names})
})
but the weird thing is that in the backend the names is an array holding the names of uploaded files but in the frontend the response is an object with a lot of data like this. it has the names array in it but I want to stop sending this chunk of data from my backend and only send the file names and the response format should only be json
config: {url: "http://localhost:8090/adminendpoint/uploadfile", method: "post", data: FormData, headers: {…}, transformRequest: Array(1), …}
data:
names: (2) ["1603483842517-2.png", "1603483842518-3.png"]
__proto__: Object
headers: {content-length: "54", content-type: "application/json; charset=utf-8"}
request: XMLHttpRequest {readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, onreadystatechange: ƒ, …}
status: 200
statusText: "OK"
__proto__: Object
You're all set, just use the data property from the Axios response object.
console.log(r.data.names)
Axios returns a response object that contains more than just the response body. You'll get status, headers, config, request. The complete field list is availabel in Axios docs.
Also, a few side notes. You wouldn't want to set 'Content-Type': 'application/json' in React, since you're using FormData - it'll set 'Content-Type': 'multipart/form-data' behind the scenes. And in Express, if you're using res.json(), you don't have to set content type at all since that function already sets it.
Related
I want to change my axios setup to upload multiple files within it
I am trying to pass it to data if the req.file exist
But it does not work
Is there any way to access request file by req.file
What if it is defined in backend?
(Like code below)
axios({
url: URL + req.url,
method: req.method,
...(
(!req.file)
? { data: req.body }
: { data: req.file }
),
})
Add the file to a formData object, and set the Content-Type header to multipart/form-data.
var formData = new FormData();
var imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
Reference HERE
I'm integrating google drive API in my application and I'm using resumable upload approach
but i can't figure out how can i get file id after upload finished in the resumable response body
here is my code to get resumable uri
const body = JSON.stringify({
name:file.originalname,
mimeType:file.mimetype,
parents:[parent folder id]
})
const url = 'https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable'
const option = {
method: 'post',
body,
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json; charset=UTF-8',
}
}
const response = await fetch(url, option)
const resumableURI = response.headers.get('location')
and this is my code to upload my file chunks
const options = {
method: 'PUT',
headers: {
'Content-Length': file.size,
'Content-Range': `bytes ${start}-${end - 1}/${length}`,
},
body: file.buffer, // contents of the chunk
};
const response = await fetch(RESUBMALEURI, options)
this is the response i got from api after upload complete
response: Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]: { body: [PassThrough], disturbed: false, error: null },
[Symbol(Response internals)]: {
url: 'https://www.googleapis.com/upload/drive/v3/files?
uploadType=resumable&upload_id=ADPycdvajyaSOgYUjPmFgZIbi-
vbjM0U7xHe0yLy1eahXOC1Zq06K7ZFN2O0c_IKRdEJfa-WFc8DwE814cjV0nhCv0U',
status: 200,
statusText: 'OK',
headers: [Headers],
counter: 0
}
}
}
is there any option i can add to request of resubmale uri or upload request itself to return the file id in the end
When I saw your script and your additional response value, I'm worried that you might have retrieved the response value using console.log(response) from const response = await fetch(RESUBMALEURI, options). If my understanding is correct, in that case, unfortunately, such a response is obtained.
If your script for the resumable upload the file works fine and the upload is completely finished, how about the following modification?
From:
const response = await fetch(RESUBMALEURI, options)
To:
const response = await fetch(RESUBMALEURI, options)
const res = await response.json();
console.log(res);
// console.log(res.id); // If you want to retrieve only the file ID, you can use this.
By this modification, when at the last request, you can obtain the following value.
{
kind: 'drive#file',
id: '###',
name: '###',
mimeType: '###'
}
Note:
By the way, in your 1st request, the location is put in the variable of resumableURI. But in your script for uploading the file content, you are using the RESUBMALEURI as the endpoint. If your actual situation uses this, please modify this. Please be careful about this.
Reference:
node-fetch
I have a external API request as given below.
Now I need to write this postman API into an axios API call. But I tried to do many alternative things, but nothing seems to work.
The below code explain the current code I tried to do.
const url = `${this._url}/rest/v1.0/files?project_id=${projectId}`;
const response = await Axios.default.post(
url,
{
file: {
parent_id: +parentId,
data: file,
},
},
{
headers: {
Authorization: `Bearer ${updatedToken}`,
'Content-Type': 'multipart/form-data',
'Procore-Company-Id': company.id,
},
maxBodyLength: Infinity,
maxContentLength: Infinity,
}
);
using form-data
const form = new FormData();
form.append( 'my_file', fs.readFileSync('/foo/bar.jpg') );
// In Node.js environment you need to set boundary in the header field 'Content-Type' by calling method `getHeaders`
const formHeaders = form.getHeaders();
axios.post('http://example.com', form, {
headers: {
...formHeaders,
},
})
.then(response => response)
.catch(error => error)
I am running my React js web app in one port 3000.
For node server I am using 4000.
While calling fetch method it returns `400 Bad request'.
Error
POST http://localhost:4006/auth/admin 400 (Bad Request)
react code npm started in 3000 port
fetch('http://localhost:4000/auth/admin',
{ mode: 'no-cors',
method: "POST",
body: JSON.stringify({
username:"admin",
password:"1234"
}),
headers: {
"Content-Type": "application/json",
'Accept': 'application/json, text/plain, */*',
credentials: "omit", //
// "Content-Type": "application/x-www-form-urlencoded",
},
})
.then((response) => console.log(response));
node code running in 4000 port
const passport = require("passport");
const route = require("../constants/routeStrings");
const keys = require("../config/keys");
const processStatus = require("../constants/processStatus");
const success = {
status: processStatus.SUCCESS
};
const failute = {
status: processStatus.FAILURE
};
module.exports = app => {
app.post('/auth/admin', passport.authenticate("local"), (req, res) => {
res.send(success);
});
};
Do not stringify the body. Change from
body: JSON.stringify({
username:"admin",
password:"1234"
}),
to
body: {
username:"admin",
password:"1234"
},
The 400 response is raised by passport since it is unable to read your params. You need to tell your "node" app to parse them before your actual routes.
// Import body parser, you should read about this on their git to understand it fully
const parser = require('body-parser');
const urlencodedParser = parser.urlencoded({extended : false});
// before your routes
app.use(parser .json());
app.use(urlencodedParser) // This will parse your body and make it available for your routes to use
Then do your other calls.
Also, make sure that you are sending username and password keys, otherwise read the documentation on how to change these key names to something else
I suffered long hours, but I overcame it throw writing those lines of code blocks. I successfully send the request to the server's controller, hopefully yours: make it try.
First define a async function to make POST request:
async function _postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
referrerPolicy: 'no-referrer',
headers: {
"Content-type": "application/json; charset=UTF-8"
},
body: JSON.stringify(data)
});
return response.json();
}
Now create a request JSON payload:
let requestPayload = {
propertyName1: 'property value1',
propertyName2: 'property value23',
propertyName3: 'property value',
So on
}
Note: Request model will be your desired model, what request payload you actually send.
Now make a request using this payload including your end point URL:
_postData('http://servername/example', requestPayload )
.then(json => {
console.log(json) // Handle success
})
.catch(err => {
console.log(err) // Handle errors
});
100% worked on my project.
I have an API endpoint that lets the client post their csv to our server then post it to someone else server. I have done our server part which save uploaded file to our server, but I can't get the other part done. I keep getting error { message: 'File not found', code: 400 } which may mean the file never reach the server. I'm using axios as an agent, does anyone know how to get this done? Thanks.
// file = uploaded file
const form_data = new FormData();
form_data.append("file", fs.createReadStream(file.path));
const request_config = {
method: "post",
url: url,
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios(request_config);
Update
As axios doc states as below and the API I'm trying to call requires a file
// data is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
// When no transformRequest is set, must be of one of the following types:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - Browser only: FormData, File, Blob
// - Node only: Stream, Buffer
Is there any way to make axios send a file as a whole? Thanks.
The 2 oldest answers did not work for me. This, however, did the trick:
const FormData = require('form-data'); // npm install --save form-data
const form = new FormData();
form.append('file', fs.createReadStream(file.path));
const request_config = {
headers: {
'Authorization': `Bearer ${access_token}`,
...form.getHeaders()
}
};
return axios.post(url, form, request_config);
form.getHeaders() returns an Object with the content-type as well as the boundary.
For example:
{ "content-type": "multipart/form-data; boundary=-------------------0123456789" }
I'm thinking the createReadStream is your issue because its async. try this.
Since createReadStream extends the event emitter, we can "listen" for when it finishes/ends.
var newFile = fs.createReadStream(file.path);
// personally I'd function out the inner body here and just call
// to the function and pass in the newFile
newFile.on('end', function() {
const form_data = new FormData();
form_data.append("file", newFile, "filename.ext");
const request_config = {
method: "post",
url: url,
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios(request_config);
});
This is what you really need:
const form_data = new FormData();
form_data.append("file", fs.createReadStream(file.path));
const request_config = {
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios
.post(url, form_data, request_config);
In my case, fs.createReadStream(file.path) did not work.
I had to use buffer instead.
const form = new FormData();
form.append('file', fs.readFileSync(filePath), fileName);
const config = {
headers: {
Authorization: `Bearer ${auth.access_token}`,
...form.getHeaders(),
},
};
axios.post(api, form.getBuffer(), config);
I have made an interceptor you can connect to axios to handle this case in node: axios-form-data. Any feedback would be welcome.
npm i axios-form-data
example:
import axiosFormData from 'axios-form-data';
import axios from 'axios';
// connect axiosFormData interceptor to axios
axios.interceptors.request.use(axiosFormData);
// send request with a file in it, it automatically becomes form-data
const response = await axios.request({
method: 'POST',
url: 'http://httpbin.org/post',
data: {
nonfile: 'Non-file value',
// if there is at least one streamable value, the interceptor wraps the data into FormData
file: createReadStream('somefile'),
},
});
// response should show "files" with file content, "form" with other values
// and multipart/form-data with random boundary as request header
console.log(response.data);
I had a same issue, I had a "pdf-creator-service" for generate PDF document from html.
I use mustache template engine for create HTML document - https://www.npmjs.com/package/mustache
Mustache.render function returns html as a string what do I need to do to pass it to the pdf-generator-service ? So lets see my suggestion bellow
//...
async function getPdfDoc(props: {foo: string, bar: string}): Promise<Buffer> {
const temlateFile = readFileSync(joinPath(process.cwd(), 'file.html'))
mustache.render(temlateFile, props)
const readableStream = this.getReadableStreamFromString(htmlString)
const formData = new FormData() // from 'form-data'
formData.append('file', options.file, { filename: options.fileName })
const formHeaders = formData.getHeaders()
return await axios.send<Buffer>(
{
method: 'POST',
url: 'https://pdf-generator-service-url/pdf',
data: formData,
headers: {
...formHeaders,
},
responseType: 'arraybuffer', // ! important
},
)
}
getReadableStreamFromString(str: string): Readable {
const bufferHtmlString = Buffer.from(str)
const readableStream = new Readable() // from 'stream'
readableStream._read = () => null // workaround error
readableStream.push(bufferHtmlString)
readableStream.push(null) // mark end of stream
return readableStream
}
For anyone who wants to upload files from their local filesystem (actually from anywhere with the right streams architecture) with axios and doesn't want to use any external packages (like form-data).
Just create a readable stream and plug it right into axios request function like so:
await axios.put(
url,
fs.createReadStream(path_to_file)
)
Axios accepts data argument of type Stream in node context.
Works fine for me at least in Node v.16.13.1 and with axios v.0.27.2