How can i upload image to server using axios in react native? - javascript

I want to upload an image file to the server in react native, how can i do so?
Here is my code :
In my index.js Which is my entry point I have set axios default configurations :
axios.defaults.baseURL = BaseUrl;
axios.defaults.headers.common['Content-Type'] = 'application/json';
axios.defaults.headers.common['Accept'] = 'application/json';
Now in my profileEdit.js, where I need to upload a profile image
let data = new FormData();
data.append('profile_picture',
{uri: imageResponse.uri, name: imageResponse.fileName, type: 'image/jpg'});
// imageResponse is a response object that I m getting from React native ImagePicker
axios.post('profile/picture/', data,
{
headers: {
"Authorization": "JWT " + this.state.token,
'content-type': 'multipart/form-data',
}
}).then(response => {
console.log('Profile picture uploaded successfully', response);
}).catch(error => {
console.log('Failed to upload profile image', error);
console.log('Error response',error.response);
});
But this giving me network error, while other APIs are working fine.
I followed the solution given here How to upload image to server using axios in react native?
This is the error response I am getting.
And my request header is like this
I don't want to use any other package such as react native fetch blob
More links that I followed :
axios post request to send form data
Can anyone please tell me where I m doing wrong or how shall I approach to this problem. ty

I think your header for the Axios POST request may be incorrect since you're using a FormData() constructor to store your image data:
You may want to try the following instead:
let data = new FormData();
data.append('profile_picture',{
uri: imageResponse.uri,
name: imageResponse.fileName,
type: 'image/jpg'}
);
axios.post('profile/picture/', data,
{
headers: {
'content-type': `multipart/form-data; boundary=${data._boundary}`,
...data.getHeaders()
}
}
)

For me simply work
const oFormData = new FormData();
oFormData.append("image", {
uri: images.uri,
type: images.type,
name: images.fileName
});
axios.post(servicesUrl.imageupload, oFormData);

Related

Cannot update picture but getting 200 status

I would like to update a profile picture. The problem is when I send the image through axios to my server I get a 200 message. However, the profile picture is not updated.
I know the issue has something to do with my frontend code because when it try to upload a picture using Postman, the image is correctly updated.
This is the code I am using to send the image:
const handleSubmit = e => {
e.preventDefault();
let profileData = new FormData()
profileData.append('profilePic', {
uri: fileDataURL,
type: 'multipart/form-data',
name: 'profile_pic.png',
});
updateProfilePic(profileData, updatedProfileInfo.user_id)
}
and the axios request sending the image to the server:
const updateProfilePic = (profilePicData, user_id) => {
console.log('formData contains', ...profilePicData)
const headers = {
'accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.8',
'Content-Type': `multipart/form-data`,
}
const base_url = 'http://127.0.0.1:8000/update_profile/'
axios.patch(`${base_url}${user_id}/`,profilePicData, {
headers,
})
.then( res => {
console.log('resp', res)
})
}
This is what I have in fileDataURL:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/...
In a nutshell I know that everything that happens before the code I have shown is working, I upload a picture, I get the image base64 string and append that to profileData

Unable to get video file for S3 upload. (using Expo Camera)

I have been stuck with trying to upload a video to S3 for a while and was hoping to get some pointers. Currently, what I've read and was told is that we need to send an actual file to S3 and not the url (which we might do if we were sending it to the backend before aws).
I am trying to do this by
const getBlob = async (fileURi) => {
console.log('THIS IS IT', fileURi);
const resp = await fetch(fileURi);
const videoBody = await resp.blob();
console.log(videoBody);
};
getBlob(video.uri);
The problem I am having is I am unable to actually get the video file. When I stop recording a video with await camera.stopRecording(); what I get in return is
Object {
"uri": "file:///path/20DD0E08-11CA-423D-B83D-BD5ED40DFB25.mov",
}
Is there a recommended approach in order to successfully get the actual file in order to send it to S3 through the client?
The way I am trying to currently send the video which doesn't work is:
const formData = new FormData();
formData.append('file', video.uri);
await fetch(url, {
method: 'POST',
body: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
url: refers to the presignedUrl we get in return from aws.
P.S - Sending to the server through a fetch call does work but I noticed this approach also leave the User waiting for 10+ seconds since I need to send the video to the server then wait for it to finish uploading in AWS.
Thank you for all the help.
If I understand correctly you know how to upload file to your own server, but you want to send it directly to S3.
In that case I would suggest to use presigned URLs. https://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html
You can generate presigned URL on your backend, it is basically regular URL pointing to S3 file and some key values. You need to send those values to mobile app and do the same fetch call you are already using, but replace url with the one generated on backend and add all key-values to FormData.
Example for node backend would look like this
import AWS from 'aws-sdk';
...
const client = new AWS.S3(config);
...
const presignedUrl = client.createPresignedPost({
Bucket: 'example-bucket-name',
Fields: { key: 'example-file-name' },
});
and in mobile app you would
const form = new FormData();
Object.keys(presignedUrl.fields).forEach(key => {
form.append(key, presignedUrl.fields[key]);
})
form.append('file', fileToUpload);
await fetch(presignedUrl.url, {
method: 'POST',
body: form,
headers: {
'Content-Type': 'multipart/form-data'
}
})
My solutions. Please review the sample application. https://github.com/expo/examples/tree/master/with-aws-storage-upload
const response = await fetch(video.uri);
const blob = await response.blob();
const params = {
Bucket: myBucket,
Metadata: {
long: long.toString(),
lat: lat.toString(),
size: videoSize.toString()
},
Key: myKey,
Body: blob
};

How to convert the string type from an API response to an image file - ����\u0000\u0010JFIF\u0000\u0001\u0001\u0000\u0000\u0001 -

I have used https://graph.microsoft.com/beta/me/photo/$value API to get the profile picture of the outlook user. I get an image on running the above API in the rest-client. The content-type of the API is "image/jpg"
But, in Node.js, the response of the API is as follows:
����\u0000\u0010JFIF\u0000\u0001\u0001\u0000\u0000\u0001\u0000\u0001\u0000\u0000��\u0000�\u0000\u0005\u0005\u0005\u0005\u0005\u0005\u0006\u0006\u0006\u0006\b\t\b\t\b\f\u000b\n\n\u000b\f\u0012\r\u000e\r\u000e\r\u0012\u001b\u0011\u0014\u0011\u0011\u0014\u0011\u001b\u0018\u001d\u0018\u0016\u0018\u001d\u0018+"\u001e\u001e"+2*(*2<66<LHLdd�\u
I used 'fs' to create an image file. The code is as follows:
const options = {
url: "https://graph.microsoft.com/beta/me/photo/$value",
method: 'GET',
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${locals.access_token}`,
'Content-type': 'image/jpg',
}
};
request(options, (err, res, body) => {
if(err){
reject(err);
}
console.log(res);
const fs = require('fs');
const data = new Buffer(body).toString("base64");
// const data = new Buffer(body);
fs.writeFileSync('profile.jpg', data, (err) => {
if (err) {
console.log("There was an error writing the image")
}
else {
console.log("The file is written successfully");
}
});
});
The file is written successfully, but the .jpg image file generated is broken. I am unable to open the image.
The output of the image file is as follows:
77+977+977+977+9ABBKRklGAAEBAAABAAEAAO+/ve
You can do this by streaming the response like this,
request(options,(err,res,body)=>{
console.log('Done!');
}).pipe(fs.createWriteStream('./profile.jpg'));
https://www.npmjs.com/package/request#streaming
https://nodejs.org/api/fs.html#fs_class_fs_writestream
The reason for this is that by default, request will call .toString() on the response data. In case of binary data, like a RAW JPEG, this isn't what you want.
It's also explained in the request documentation (albeit vaguely):
(Note: if you expect binary data, you should set encoding: null.)
Which means that you can use this as well:
const options = {
encoding : null,
url : "https://graph.microsoft.com/beta/me/photo/$value",
method : 'GET',
headers : {
'Accept' : 'application/json',
'Authorization' : `Bearer ${locals.access_token}`,
'Content-type' : 'image/jpg',
}
};
However, streaming is probably still the better solution, because it won't require the entire response being read into memory first.
Request is deprecated. You can do this with axios;
// GET request for remote image in node.js
axios({
method: 'get',
url: 'http://example.com/file.jpg',
responseType: 'stream'
})
.then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});

How to send image from image Uri through HTTP request? (React Native and Django Backend)

I’m using Expo’s image picker and I’m getting this output:
Object {
"cancelled": false,
"height": 468,
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540jbaek7023%252Fstylee/ImagePicker/9a12f0a3-9260-416c-98a6-51911c91ddf4.jpg",
"width": 468,
}
I could render my image, but I just realized that the URL is the phone’s local URI.
I’m using Redux-Thunk and Axios to send HTTP POST request:
export const sendPost = ( imageUri, title, content ) => async dispatch => {
let response = await axios.post(`${ROOT_URL}/rest-auth/registration/`, {
image, <<<<- I can't put image uri here :( it's LOCAL path
title,
content
})
if(response.data) {
dispatch({ type: POST_CREATE_SUCCESS, payload: response.data.token })
} else {
dispatch({ type: POST_CREATE_FAIL })
}
}
UPDATE I changed a request call
let headers = { 'Authorization': `JWT ${token}`};
if(hType==1) {
headers = { 'Authorization': `JWT ${token}`};
} else if (hType==2) {
headers = { 'Authorization': `Bearer ${token}`};
}
let imageData = new FormData();
imageData.append('file', { uri: image });
let response = await axios.post(`${ROOT_URL}/clothes/create/`, {
image: imageData,
text, bigType, onlyMe ...
}, {headers});
!! sorry for the complication but image variable name; image is uri for the image. I didn't want to change the name of original variable name
and on server, it's printing
'image': {'_parts': [['file', {'uri': 'file:///data/user/0/host.exp.exponent
/cache/ExperienceData/%2540jbaek7023%252Fstylee/
ImagePicker/78f7526a-1dfa-4fc9-b4d7-2362964ab10d.jpg'}]]}
I found that gzip compression is a way to send image data. Does it help?
Another option is to convert your image to base64 and send the string. Downsize is that usually the base64 strings has a bigger size than the image itself.
Something like this:
function readImage(url, callback) {
var request = new XMLHttpRequest();
request.onload = function() {
var file = new FileReader();
file.onloadend = function() {
callback(file.result);
}
file.readAsDataURL(request.response);
};
request.open('GET', url);
request.responseType = 'blob';
request.send();
}
It has to be a local URI, there's no issues with that, how else are you going to point to the image.
Now to upload the image you should first wrap it inside of FormData:
// add this just above the axios request
let img = new FormData();
img.append('file', { uri: imageUri });
Then inside of your axios request body add:
image: img,
EDIT: This question in it's current form is unanswerable.
I'm using the same Expo’s image picker with React-native in one of my projects as OP and everything works just fine, there's no issues with FormData.
After having talked with OP in a stackoverflow chat, couple of days ago, and stripping the request down to just an image, the server started throwing encoding errors:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 168: invalid start byte
So the issue is with OP's Django backend not being setup correctly in parsing the image, and not with the sending of the image itself - which makes the question unanswerable.
you cant use react-native-fetch-blob .....
import RNFetchBlob from " react-native-fetch-blob"
PostRequest(PATH){
RNFetchBlob.fetch('POST', "[URL]", {
"x-session-id": "SESSION_ID", //or Custom headers
'Content-Type': 'multipart/form-data',
}, [
{ name: 'image', filename: 'vid.jpeg', data: RNFetchBlob.wrap(PATH) },
// custom content type
]).then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
// error handling ..
})
}
}
for reference react-native-fetch-blob

Uploading to Cloudinary API - Invalid file parameter

I am working on integrating Cloudinary with my React Native app and am running into a problem when I go to upload using the Cloudinary API. I'm using React Native Image Picker to select an image from the camera roll and using that I get a source uri - example below.
I am getting an error response back from Cloudinary and I'm not sure what it's referring to. "Invalid file parameter. Make sure your file parameter does not include '[]'"
When I use the debugger, I can console log out all the params I am sending in the body of my request. Any suggestions would be much appreciated!
source.uri: /Users/IRL/Library/Developer/CoreSimulator/Devices/817C678B-7028-4C1C-95FF-E6445FDB2474/data/Containers/Data/Application/BF57AD7E-CA2A-460F-8BBD-2DA6846F5136/Documents/A2F21A21-D08C-4D60-B005-67E65A966E62.jpg
async postToCloudinary(source) {
let timestamp = (Date.now() / 1000 | 0).toString();
let api_key = ENV.cloudinary.api;
let api_secret = ENV.cloudinary.api_secret
let cloud = ENV.cloudinary.cloud_name;
let hash_string = 'timestamp=' + timestamp + api_secret
let signature = CryptoJS.SHA1(hash_string).toString();
let upload_url = 'https://api.cloudinary.com/v1_1/' + cloud + '/image/upload'
try {
let response = await fetch(upload_url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
file: {
uri: source.uri,
type: 'image/jpeg'
},
api_key: api_key,
timestamp: timestamp,
signature: signature
})
});
let res = await response.json();
console.log(res);
} catch(error) {
console.log("Error: ", error);
}
}
UPDATE
So I now have base64 encoding working, I think, but I am still getting the same error.
var wordArray = CryptoJS.enc.Utf8.parse(source.uri);
var file = CryptoJS.enc.Base64.stringify(wordArray);
try {
let response = await fetch(upload_url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
file: {
uri: file,
type: 'image/jpeg;base64'
},
api_key: api_key,
timestamp: timestamp,
signature: signature
})
});
So it turns out the source data I was passing in was not formatted correctly. I was able to pass it in from the ImagePicker plugin I was using as an already formatted data URI (the ImagePicker example comes with two ways to capture your source file and I was using the wrong one). I was able to get rid of the CryptoJS stuff and simply pass in file: source.uri
If you are using axios, make sure to include {'X-Requested-With': 'XMLHttpRequest'} in your request headers. eg.
const uploadAgent = axios.create({
baseURL: 'https://api.cloudinary.com',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});

Categories