Uploading videos using formdata in react native - react-native

Has anyone successfully uploaded a video via React Native Formdata()? The code below attempts to upload a .mov file from the camera roll URI but in fact only the first frame of the video (a JPEG) gets uploaded. What's the issue here?
var movVideo = {
uri: uriFromCameraRoll,
type: 'video/quicktime',
name: 'something.mov',
};
var body = new FormData();
body.append('video', movVideo);
body.append('title', 'A beautiful video!');
fetch('https://mysite/upload_asset', {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
body: body,
}).then((response) => response.json())
.then((responseJson) => {
//only the first frame of the video got uploaded
console.log(responseJson);
});

Had the same issue. Looks like React Native does not return the correct stream for videos with asset library URIs. Pictures seem to work fine. I would need to dig deeper before submitting an issue though.
I suggest you take a look at react-native-fetch-blob, which provides an improved fetch polyfill with Blob support. This implementation handles videos from the camera roll just fine. Also, the changes needed to use this module are minimal (include the polyfill, wrap URI with RNFetchBlob.wrap).

Related

Axios network error even though the post request returns 200

After enabling CORS and everything on my server, the error persists.
In other forms inside my app, uploading pictures works... but in this exact form, on iPhone it works absolutely fine, but on android after submitting, all I get is a "network error" although the post returns 200. I think this is an axios problem. Only on android I get this issue.
my code is the following:
const data = new FormData()
data.append('subject_id', this.props.navigation.getParam('id'))
data.append('name', this.state.title)
data.append('progress', this.state.progress * 100)
data.append('description', this.state.description)
data.append('date', this.state.date)
data.append('image', {
uri: this.state.image,
type: 'image/jpeg',
name: 'image'
});
axios.post('https://example.com/api/auth/createTask', data, {
headers: {
'Authorization': access,
"Content-Type": "multipart/form-data"
},
}).then(res => {
this.props.navigation.navigate('ViewHW', { id: res.data.id })
}).catch(res => {
console.log(res)
})
I would really appreciate the help on this one.
I doubt that it's an axios issue.
If you're using an image picker or camera make sure you check the documentation as the path to the file selected differs between android and iOS.
Make sure you change the path of the item based on platform.OS === 'android'.
It should be clearly described in the docs of whatever you're using.
This ended up being a problem with react-native. The bug is now patched (the new version 0.63.3)

React Native Uploading Video to YouTube (Stuck at Processing)

I am attempting to upload video files to YouTube using their v3 API and their MediaUploader. It works in my ReactJS application, but not in my React Native application. When uploading via React Native, the upload completes, then stalls at 100%. In my YouTube account, I can see the new video file, but it is stuck at "Video is still being processed."
I believe the issue may be that I need to send a video file and not an object with a video uri but I don't know how to get around that.
I am using the YouTube MediaUploader from the CORS example at https://github.com/youtube/api-samples/blob/master/javascript/cors_upload.js I am using an OAuth 2.0 client Id, and this setup works correctly when using the ReactJS app via my website. I am using React Native Expo with Camera, which returns me an Object with a URI, for example:
Video File: Object {
"uri": "file:///var/mobile/Containers/Data/Application/353A7969-E2A8-4C80-B641-C80B2B029555/Library/Caches/ExponentExperienceData/%2540dj_walksalot%252Fwandereo/Camera/E971DFEC-AB3E-4B6D-892F-9027AFE47A1A.mov",
}
This file can be viewed in the application, and I can even successfully send this to my server for playback on the web app and in the React Native app. However, sending this object in the MediaUploader does not work. It will take an appropriate amount of time to upload, but then sits at 100%, while my YouTube account will show it has received the video with the correct metadata, but the video itself remains stuck at "Video is still being processed."
video_file: Object {
"uri": "file:///var/mobile/Containers/Data/Application/353A7969-E2A8-4C80-B641-C80B2B029555/Library/Caches/ExponentExperienceData/%2540dj_walksalot%252Fwandereo/Camera/E971DFEC-AB3E-4B6D-892F-9027AFE47A1A.mov",
}
export const uploadToYouTube = (access_token, video_file, metadata) => async (dispatch) => {
...cors_upload...
var uploader = new MediaUploader({
baseUrl: `https://www.googleapis.com/upload/youtube/v3/videos?part=snippet%2Cstatus&key=API_KEY`,
file: video_file,
token: access_token,
metadata: metadata,
contentType: 'video/quicktime',
// contentType: 'application/octet-stream',//"video/*",
// contentType = options.contentType || this.file.type || 'application/octet-stream';
params: {
part: Object.keys(metadata).join(',')
},
onError: function(data) {
// onError code
let err = JSON.parse(data);
dispatch(returnErrors(err.message, err.code))
console.log('Error: ', err);
},
onProgress: function(progressEvent){
// onProgress code
let percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
dispatch({
type: UPLOAD_PROGRESS,
payload: percentCompleted
});
},
onComplete: function(data) {
console.log('Complete');
// onComplete code
let responseData = JSON.parse(data);
dispatch({
type: UPLOAD_YOUTUBE_VIDEO,
payload: JSON.parse(data)
})
dispatch({
type: UPLOAD_PROGRESS,
payload: 0
});
}
});
uploader.upload();
}
Similar to my currently-working web app, after completing the upload, the "onComplete" function should fire, and YouTube should process the video. This does not happen. I believe it's because I'm attaching an object with a URI and not the actual file.
I was able to solve this from a post at Expert Mill by Joe Edgar at https://www.expertmill.com/2018/10/19/using-and-uploading-dynamically-created-local-files-in-react-native-and-expo/
By using fetch and .blob() I was able to convert the URI object to a data object and upload. Additional code:
const file = await fetch(video_file.uri);
const file_blob = await file.blob();
No need to install RNFetchBlob since this is in the Expo SDK.

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.