I have a component which processes and uploads images. Currently I process the image on my backend and then send it to my frontend and then upload it from there. I would like to do everything on my backend. The only issue is that the upload endpoint requires FormData() object. I found an npm package form-data which I'm using on my backend now, but I'm still getting error.
This is how it currently works:
// frontend logic:
const data = await uploadImage(img);
const file = new File([Buffer.from(data)], `img-${i}.webp`, {
type: "image/webp",
});
const formData = new FormData();
formData.append("path", "images");
formData.append("files", file, file.name);
await axios
.post("http://localhost:1338/api/upload", formData, {
headers: { authorization: `Bearer ${jwtToken}` },
})
.then(({ data }) => {
console.log(data);
})
.catch(console.log);
//
//
// backend logic:
const data = await processImage(img.url);
return data;
This is what im trying to do:
// frontend logic:
const data = await uploadImage(img);
//
//
// backend logic:
const data = await processImage(img.url);
const formData = new FormData();
formData.append("path", "images");
formData.append("files", data, "file.name");
await axios
.post("http://localhost:1338/api/upload", formData, {
headers: { authorization: `Bearer ${process.env.JWT_TOKEN}` },
})
.then(({ data }) => {
console.log(data);
})
.catch(console.log); // I get error: 413 Payload Too Large
I'm trying to do it with the same image which works with the first method. Perhaps I need to create a new File(), but I couldn't find any npm packages which worked for that. What should I do to get this working?
Related
I am consuming an api that asks me to send a filter series within a formData, when doing the tests from Postman everything works without problem, I tried with other libraries and it also works without problem, but when trying to do it from axios the information does not return with the filters.
This is the code I am using:
const axios = require('axios');
const FormData = require('form-data');
let data = new FormData();
data.append('filtro_grafica', '2,0,0,0');
let config = {
method: 'get',
url: 'https://thisismyurl/filter',
headers: {
'Authorization': 'JWT MYTOKEN',
...data.getHeaders()
},
data : data
};
axios(config)
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch((error) => {
console.log(error);
});
You can send Form-data using get method, but the most servers, will reject the form data.
However it is not recommended anymore. The reason is, first because it is visible in the URL and browsers can cache them in it’s history backstacks, and second reason is because browsers have some limitations over the maximum number of characters in url.
If you are to send only few fields/input in the forms you can use it but if you have multiple inputs you should avoid it and use POST instead.
At the end it depends on your own usecase. Technically both GET and POST are fine to send data to server.
replace get with post
const axios = require('axios');
const FormData = require('form-data');
let data = new FormData();
data.append('filtro_grafica', '2,0,0,0');
let config = {
method: 'post',
url: 'https://thisismyurl/filter',
headers: {
'Authorization': 'JWT MYTOKEN',
...data.getHeaders()
},
data : data
};
axios(config)
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch((error) => {
console.log(error);
});
I'm trying to upload a file to Cloudinary using fetch from my front-end. I've tried piecing together the way to do it from the documentation and StackOverflow answers, but I get a 400 error:
export async function uploadImageToCloudinary(file: File) {
const url = `https://api.cloudinary.com/v1_1/${cloudName}/upload`;
const fetched = await fetch(url, {
method: "post",
body: JSON.stringify({
file,
cloud_name: cloudName,
upload_preset: "unsigned",
}),
});
const parsed = await fetched.json()
console.log({
parsed // 400 error, message: "Upload preset must be specified when using unsigned upload"
});
}
It says upload preset must be specified, so I must have the above code wrong. My Cloudinary Settings have the 'unsigned' upload preset here:
It works if I replace the body: JSON.stringify(...) with const data = new FormData().... I don't know why, but this works:
export async function uploadImageToCloudinary(file: File) {
const url = `https://api.cloudinary.com/v1_1/${cloudName}/upload`;
const data = new FormData();
data.append('file', file);
data.append('upload_preset', 'unsigned');
const fetched = await fetch(url, {
method: "post",
body: data,
});
const parsed = await fetched.json()
console.log({
parsed // 200, success!
});
}
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
I am trying to send an image file and data (object or array) to a backend with react native. I tried using fetch and the code below and got it to send an image to backend. But my target is to send the image and data together. How can I achieve this?
uploadPhoto = async (response) => {
const formData = new FormData();
formData.append('fileToUpload', {
uri: response.path,
name: 'image',
type: response.mime,
imgPath: response.path
});
const infos={ad:'onur',soyad:'cicek'};
try {
const rest = await fetch('https://www.birdpx.com/mobile/fotografyukle/'+this.state.user.Id, {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-type': 'multipart/form-data' },
body: formData
});
const gelenVeri = await rest.text();
let convertedVeri=JSON.parse(gelenVeri);
console.log(convertedVeri);
return false
} catch (err) {
console.log(err)
}
};
I need to post const infos={ad:'onur',soyad:'cicek'}; and the image.
You can pass it in formData itself
formData.append('other_infos', infos);
Here other_infos will be key that required to extract from backend, you can append n number of parameters in FormData
You can do it by adding other data to the FormData.
like in the example
formData.append('infos', infos);
Hi Everybody i making a web frontend using expo SDK 39.0.2 but i have a big problend and really i not found a fix, im trying to send image like formdata to my backend but in mi backend this is null; this is not a problem of my api rest, i send a similar tequest from postman and all is’t working… but not working from formdata and I think : “this is problem with my way of to send formdata”
this is my code:
//Component code
const imagepreview = async()=>{
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: false,
aspect: [4, 3],
quality: 0.6,
});
console.log(result)
if(result.cancelled == false){
setImage(result.uri)
let uriParts = result.uri.split('.');
let fileType = uriParts[uriParts.length - 1];
settype(fileType)
}
}
const sendData = async()=>{
// Upload the image using the fetch and FormData APIs
let formData = await new FormData();
// Assume "photo" is the name of the form field the server expects
await formData.append('photo', {
name: `photo.${type}`,
type: `image/${type}`,
uri: image,
});
const send = await user.changeprofilepicture(formData)
my http request code:
async changeprofilepicture(formdata){
console.log(formdata)
const token = JSON.parse(localStorage.getItem('user-token'))
let url = baseurl+'changeprofilepicture'
let options = {
headers: {
'content-type': 'multipart/form-data'
}
}
await axios.post(url, formdata, options)
await axios.post(url, {
photo: formdata
}, {headers :
{'Content-Type':undefined}})
}
i have two http request for im triying two ways for solved my broblem but does not works, only works at postman
really, thanks for te answers
Finally I solved..
I Change expo image picker for expo document picker like this:
const imagepreview = async()=>{
const trye = await DocumentPicker.getDocumentAsync({type: 'image/*'})
setFile(trye.file)
setImage(trye.uri)
console.log (trye)
}
const sendData = async()=>{
formData.append('photo', file);
console.log(file)
return await fetch('http://127.0.0.1:3333/api/changeprofilepicture', {
method: 'POST',
body: formData,
});
}