fetch sends [object Object] instead of File object - react-native

I'm using Expo and its ImagePicker to grab the image from gallery. It returns both uri and base64.
Now I want to upload the image in a multipart/form-data request.
The problem is that the server only accepts File while below code sends [object Object] instead.
Image of the request
const formData = new FormData();
const data = {
jwt,
};
formData.append('message', JSON.stringify(data));
formData.append('avatar', {
uri: avatar,
type: 'image/png',
name: 'avatar.png'
});
fetch(url, {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json',
},
})
Since I'm using Expo I'm limitted to libraries that it supports. Also adding Content-Type header doesn't work at all and server can't even recognize the message.

If you see that file being sent as [object object] in your request params, that might occur due to two reasons:
The file that you are sending is not a file (or not a file object).
A FormData should only receive a File or a Blob object in order to be sent on a request.
Note that you have the right keys on your object and that it is indeed a File or a Blob.
As mentioned, it might be the Content-Type header which should not be set

For React, if you want to upload image and avoid [object object] error, there is a need to setFile for input type handleChange
const file = event.target.files[0]
setFile({
picturePreview: URL.createObjectURL(event.target.files[0]),
pictureAsFile: event.target.files[0]
})
And then calling in formData like:
formData.append('file_attachment', file.pictureAsFile)
Full working example here: https://youtu.be/yTGXNvHQ4BQ

Related

Is there anyway to manuallyAddFile in Vue2-Dropzone while knowing only the url of the file and doing 1 request (incl Vue2-Dropzone requests)

My problem with Vue2-Dropzone is that assuming you have only the fileUrl at hand and you want to manuallyAdd it to the dropzone. You have to fetch the file first to get the size and filename and then pass the URL to manuallyAddFile so it will perform the fetch/render of the thumbnail.
I downloaded the Vue2-Dropzone library went through the code, checked the documentation and I can't find a way that would allow you to provide all that data and make the fetch only once.
e.g scenario
mounted: () {
const url = "https://myvizo.com/img/logo_sm.png";
const response = await axios.get('https://myvizo.com/img/logo_sm.png', { responseType: 'blob'} );
const file = { size: response.data.size, name: getFileName(response), type: getType(response) };
this.$refs.myVueDropzone.manuallyAddFile(file, url);
}
is there any way I can pass the response from my axios call to render the image/thumbnail in vue-dropzone without causing another fetch.

How to get a stream while a video is being recorded?

I'd like to upload data chunk to server while recording a video(not after recording).
I tried to go with react-native-camera or react-native-vision-camera.
but as far as I know, recordAsync method only resolves the final version of recorded video.
Is there any smart way to get video chunk or stream during recording.
or should I use react-native-fs or rn-fetch-blob or something like that?
== update ==
I could probably achieve it like it gets done in the link below.
https://medium.com/react-native-training/build-youtube-alike-livestreams-with-react-native-8dde24adf543
If your problem is with regards to uploading a large file to the server, maybe you can go with react-native-background-upload, and show a progress notification, this will upload the file even when the app is in background.
There is also a package where in chunck upload is possible by breaking the file into multiple chunks : react-native-chunk-upload
import ChunkUpload from 'react-native-chunk-upload';
const chunk = new ChunkUpload({
path: response.path, // Path to the file
size: 10095, // Chunk size (must be multiples of 3)
fileName: response.fileName, // Original file name
fileSize: response.size, // Original file size
// Errors
onFetchBlobError: (e) => console.log(e),
onWriteFileError: (e) => console.log(e),
});
chunk.digIn(this.upload.bind(this));
upload(file, next, retry, unlink) {
const body = new FormData();
body.append('video', file.blob); // param name
axios.post('url', body, {
headers: {
"Content-Type": "multipart/form-data",
"Accept": 'application/json',
// Customize the headers
"x-chunk-number": file.headers["x-chunk-number"],
"x-chunk-total-number": file.headers["x-chunk-total-number"],
"x-chunk-size": file.headers["x-chunk-size"],
"x-file-name": file.headers["x-file-name"],
"x-file-size": file.headers["x-file-size"],
"x-file-identity": file.headers["x-file-identity"]
}
}).then((res) => {
...
})

Uploading image to S3 on Postman works but it doesn't work when I use React Native Image Picker

My Rails API seems to be working fine, when I POST an image to S3 via postman.
However, when I use React Native image picker, I don't think I'm sending the parameters in the correct way.
I am currently sending the image uri as the image parameter (the uri of the image picked from the image picker). Should I be sending something else as the image parameter?
Here is a part of my async function to make a POST request to the Visions table:
let access_token = this.state.accessToken
try {
let response = await fetch('https://prana-app.herokuapp.com/v1/visions/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-User-Email': this.state.email,
'X-User-Token': this.state.accessToken
},
body: JSON.stringify({
vision: {
description: 'YOYOYOYOYO',
image: this.state.uploadFile
}
})
});
In this case, this.state.uploadfile is the response.uri that I am getting when I pick an image from Image picker, which is formatted like:
file:///Users/ozgecokyasar/Library/Developer/CoreSimulator/Devices/EDD6C498-DACD-433E-B96D-3A30BAE7BA6D/data/Containers/Data/Application/B549F09A-EB40-4D9A-B8A8-B003362BE49D/Library/Caches/ExponentExperienceData/%2540anonymous%252Fmanifestation-react-3ac1cbe2-549f-49e7-8506-ef29638d1643/ImagePicker/28EAA390-F814-4A80-A188-8592B642BEFA.jpg
I am getting a 500 error:
ActionView::Template::Error (to_model delegated to attachment, but attachment is nil):

react native fetch not sending body content

I am new to fetch in react native and followed this tutorial.
I am trying to send a json body to an private api server, I checked the server log and found out that the body content is empty.
Here is the code in react native
authenticateLogIn(){
fetch('<URL>', {
method: 'POST',
header: {'Content-Type': 'application/json', 'Accept': 'application/json'},
body: JSON.stringify({'username': '<username>', 'password':'<password>'})
})
.then((incoming) => incoming.json())
.then((response) => {
console.log(response.header);
Alert.alert(JSON.stringify(response.body));
})
.done();
Maybe because it shoueld be headers? (with the s)
It might be because your JSON body isn't being parsed correctly. bodyParser https://github.com/expressjs/body-parser is part of the middleware that parses request bodies and needs to be configured.
req.body kept coming back empty for me until I added app.use(bodyParser.json() into server.js file. Make sure you import body-parser.

Using Fetch instead of XMLHttpRequest in React Native

I was trying to upload images to S3 from my react native app by following and adapting this guide by heroku: https://devcenter.heroku.com/articles/s3-upload-node
Essentially I am using the aws-sdk on my express.js backend to generate pre-signed request for uploading images to S3 from react native.
Everything works well, so then I tried to convert the XMLHttpRequests into fetch requests, which seem to be favoured by react native. After the conversion, the files are still being uploaded to S3, but when I click on the image links, then the images wouldn't not show properly, instead an empty square is shown:
Empty square shown instead of image
More specifically it seems to be this piece of code conversion that causes it to happen:
From:
_uploadFile(file, signedRequest, url){
const xhr = new XMLHttpRequest();
xhr.open('PUT', signedRequest);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4){
if(xhr.status === 200){
console.log("UPLOAD DONE");
} else {
alert('ERROR UPLOADING');
}
}
};
xhr.send(file);
}
To:
_uploadFile(file, signedRequest, url) {
let option = {
method: "PUT",
headers: {
"Content-Type": "image/jpeg",
},
body: JSON.stringify(file)
}
fetch(signedRequest, option)
.then(res => console.log("UPLOAD DONE"))
.catch(err => console.log("ERROR UPLOADING: ", err))
}
The file object being uploaded:
{
name: "profileImage",
type: "image/jpeg",
uri: 'data:image/jpeg;base64,' + response.data, //just a base64 image string
isStatic: true
}
Could anyone shed some light on why this could be happening, or have had similar experiences? Many thanks!
In your fetch example you put a JSON string in your body. It will be sent to S3 but it will not be interpreted as an image upload. You should be able to construct a FormData object yourself and pass it to fetch as the request body, but I think using XHR is the simpler option. According to this comment it's what Facebook does as well (the comment is over a year old).
If at all possible you should also try to use local URIs instead of passing Base64 encoded data. It takes quite a while to transfer a few MB of image data between JS and native.