Upload image using fetch doesn't work in React Native (iOS) - react-native

I am working on a mobile app using React Native and posting an image on iOS doesn't work. I have hooked up my code to requestbin, setup the info.plist to allow non-https urls and other post requests are working (e.g login). For the image, all I get is a blank body for the request. Here is the code posting the image:
uploadImage = () => {
const data = new FormData();
data.append('photo', {
uri: this.state.logo.uri,
name: 'logo'
});
fetch([requestbin url here], {
method: 'post',
body: data
}).then(res => {
console.log(res);
});
for the image, I am using react-native-image-picker to get it and store it in state under the variable 'logo'. Here is that code as well
handleNewImage = () => {
var options = {
title: 'Choose new company logo',
storageOptions: {
skipBackup: true,
path: 'images'
}
};
showImagePicker(options, response => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
let source = { uri: response.uri };
// You can also display the image using data:
// let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
logo: source
});
}
});

Remember that you also should pass a name key too, like below:
let url = "",
headers = "",
method = "POST",
body = new FormData(),
uri = "URI of the picked image.";
body.append("photo", {
name: "Just a name",
uri : Platform.OS === "android" ? uri : uri.replace("file://", "")
}
);
fetch(url, method, headers, body)
.then(function (response) {
})
.catch(function (error) {
});

function uploadProfilePicture(mImage) {
var data = new FormData();
data.append('theFile', { uri: mImage.uri, name: 'profile_photo.jpg', type: 'image/jpg' });
fetch(AppConstant.BASE_URL + AppConstant.upload_media, {
method: 'POST',
body: data
})
.then((response) => response.json())
.then((responseJson) => {
var err = 'error_message' in responseJson ? true : false
if (err) {
alert(responseJson.error_message)
} else {
alert(JSON.stringify(responseJson))
}
})
.catch((error) => {
console.error(error);
alert(error)
});
}

If anyone has issues with using fetch in iOS, check out react-native-file-upload I have found it to be extremely helpful in both image uploading and regular posts.

Related

How to make form body in axios react native

I want to upload image in react native, so I use react native image picker. In my postman the api can upload image, but in mycode nothing update. in below example consume api in postman
in my code like this:
const handlePickImage = () => {
launchImageLibrary(
{
mediaType: 'photo',
quality: 0.5,
},
(response) => {
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
const { uri, type, fileName } = response?.assets?.[0];
console.log(response?.assets);
if (uri) {
setSelectedImage({
name: formik.values.companyName.replace(/\s/g, '-'),
uri,
type,
fileName,
});
setPreviewImage(uri);
} else {
console.log('Fail to pick image!');
}
}
},
);
};
This is my logic for submit data
const formData = new FormData();
formData.append('image', selectedImage?.fileName);
await handleSubmit(formData);
const handleSubmit = async (input) => {
try {
const result = await axios.patch(`${BASE_URL}/company/profile`, input, {
headers: { Authorization: `Gosnix ${DataLoginReducers?.token}` },
});
if (result.status == 200 || result.status === 'success' || result.status == 201) {
formik.resetForm();
setModalActive({ status: false });
setErrorMessage('');
navigation.goBack();
}
} catch (error) {
console.log(error);
setModalActive({ status: true, type: 'error' });
setErrorMessage(translations['please.try.again']);
}
};
anyone help me?
in your headers add "Content-Type": "multipart/form-data". When sending formdata, you need to tell the backend what type of data to expect so in this case it would be multipart/form-data.

How to upload a file in react-native iOS?

While trying to upload a file I ran into an issue on iOS, the code works fine on android. After a bit of googling, I found that it is a known issue in react-native iOS and has a bug report submitted. This is the issue. I want to know if there is any other way to upload files on iOS. Below is the snippet of code I'm using. Please let me know if there is something that can be done.
const resp = await fetch(uploadUrl, {
method: 'POST',
headers: {
'content-type': 'multipart/form-data',
},
body: file, // file is File type
});
You can something like below code snippet
function uploadProfileImage(image, token) {
const url = ServiceUrls.UPLOAD_PROFILE_IMAGE
return uploadResourceWithPost({
url,
authToken: token,
formData: createFormData(image),
})
}
const createFormData = (data) => {
const form = new FormData()
form.append('file', {
uri: Platform.OS === 'android' ? data.uri : data.uri.replace('file://', ''),
type: 'image/jpeg',
name: 'image.jpg',
})
return form
}
const uploadResourceWithPost = ({ url, authToken, formData }) => {
return handleResponse(axios.post(url, formData, defaultUploadOptions(authToken)))
}
const defaultUploadOptions = (authToken) => ({
timeout,
headers: {
'X-Auth-Token': authToken,
'Content-Type': 'multipart/form-data',
},
})
const handleResponse = (responsePromise) => {
return NetInfo.fetch().then((state) => {
if (state.isConnected) {
return responsePromise
.then((response) => {
return ResponseService.parseSuccess(response)
})
.catch((error) => {
return ResponseService.parseError(error)
})
}
return {
ok: false,
message: 'Check your network connection and try again.',
status: 408,
}
})
}
const parseSuccess = ({ data, headers }) => ({ ...data, headers, ok: true })
const parseError = ({ response }) => {
let message = 'Check your network connection and try again.'
let status = 408
if (response && response.data) {
const { data } = response
message = data.message
status = data.code
}
return { status, message }
}

Upload image to AWS presigned URL from react native

im trying to upload an image to AWS Presigned url. I can get presigned url then i can upload an image from Postman, but i try to send from React Native application, just uri info is sent (content://media/external/images/media/108721). I tried a lot of thing but i cant do it. Could you help me please?
I am using react-native-image-picker to select an image.
showImagePicker = () => {
const options = {
title: 'Profile Picture',
storageOptions: {
skipBackup: true,
path: 'images',
base64: true,
},
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
const source = { uri: response.uri };
const avatarData = response;
let presignedUrl = "mypresignedurl";
const xhr = new XMLHttpRequest()
xhr.open('PUT', presignedUrl)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('Image successfully uploaded to S3')
} else {
console.log('Error while sending the image to S3', xhr.responseText)
}
}
}
xhr.setRequestHeader('Content-Type', response.type)
xhr.setRequestHeader('content-lenght', response.fileSize)
xhr.send(response.uri);
this.setState({
avatarSource: source,
avatarData: avatarData,
imageModalVisibilty: true
});
}
});
}
I saw many example like this but i just only send uri string.
I solved this issue with another way. I had to get blob data :)
export const getBlob = async (fileUri) => {
const resp = await fetch(fileUri);
const imageBody = await resp.blob();
return imageBody;
};
export const uploadImageNew = async (uploadUrl, data) => {
const imageBody = await getBlob(data);
return fetch(uploadUrl, {
method: "PUT",
body: imageBody,
});
};
reference

Image upload with react native axios

I am trying to upload image via axios to an API but I have issues the server sends no response at all no error this is the code
image picker
const showImage = () => {
ImagePicker.showImagePicker(options, (response) => {
if (response.didCancel) {
setIsImageEdit(false);
} else if (response.error) {
} else if (response.customButton) {
} else {
const source = response;
setUserImage({
fileLink: source.uri,
});
setUploadImageFile(source.uri);
}
});
};
and code for upload via axios
setActivity(true);
const token = await getToken();
if (uploadImageFile) {
const uploadUri =
Platform.OS === 'ios'
? uploadImageFile.replace('file://', '')
: uploadImageFile;
const data = new FormData();
data.append('file', {
uri: uploadImageFile,
name: 'file',
type: 'image/jpg',
});
console.log(uploadImageFile);
console.log(data);
Axios.post('http://capi.beebl.io/user/image', data, {
headers: {
Authorization: token,
'Content-Type': 'multipart/form-data',
},
})
.then((res) => {
console.log(res);
setActivity(false);
})
.catch((err) => {
console.log(err);
setActivity(false);
});
there is no error displayed the activity indicator goes on and one and no response
I am uploading the image via postman and everything is good it uploads
try instead of uploadImageFile.replace('file://', '') this: uploadImageFile.replace('file:', '')

How to use axios to upload image from imagePicker

I trying to upload a file image to API in postman thats work fine but when a i try file image from ImagePicker didnot work.
I think doing something wrong when create formdata
Handler
ImagePicker.showImagePicker(optionsImagePicker, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
// const source = { image: response.data };
let photo = { uri: response.uri}
let formdata = new FormData();
formdata.append("product[name]", 'test')
formdata.append("product[price]", 10)
formdata.append("product[category_ids][]", 2)
formdata.append("product[description]", '12dsadadsa')
formdata.append("product[images_attributes[0][file]]", {uri: photo.uri, name: 'image.jpg', type: 'image/jpeg'})
updateProfilePic(formdata)
// You can also display the image using data:
// const source = { uri: 'data:image/jpeg;base64,' + response.data };
// this.setState({
// avatarSource: source,
// });
}
});
Service
export function uploadImageProfile(data: any): Promise<any> {
const config = {
headers: {
'Content-Type': 'multipart/form-data',
},
};
return api.post('/users/profilepic', {image: data}, config).then((res) => {
console.log(res.data);
return res.data;
});
}
Your form data must be like that.
formdata.append('file',{
uri: Platform.OS === 'android' ? photo.uri : 'file://' + photo.uri,
name: 'test',
type: 'image/jpeg' // or your mime type what you want
});
Then
axios.post('/users/profilepic', formdata, config).then((res) => {
console.log(res.data);
return res.data;
});
let formdata = new FormData();
formdata.append('file',{
uri: Platform.OS === 'android' ? photo.uri : 'file://' + photo.uri,
name: 'test',
type: 'image/jpeg'
});
use method:"POST" and spread formdata.getHeaders() into header
let reqObj = {
method: "POST",
url: 'http://example.com/upload/image',
headers: {
'x-sh-auth': token,
...formdata.getHeaders()
},
maxContentLength: Infinity,
maxBodyLength: Infinity
};
axios(reqObj).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
});
I changed how I send image to the server. Now send im base64 and in server convert to file with fs.
const uploadImage = {
imageBase64: 'data:' + response.type + ';base64,' + response.data,
};
updateProfilePic(uploadImage);
server side
async saveImageProfile(imageBase64, logedUserData) {
let base64Image = imageBase64.imageBase64.split(';base64,').pop();
let type = imageBase64.imageBase64.split('image/').pop().split(';')[0];
let newFileName = `${logedUserData.id}.${type}`;
if (imageFileFilter(type)) {
const file = await fs.writeFile('./files/' + newFileName, base64Image, { encoding: 'base64' }, function (err) {
console.log('File created');
});
const url = `${baseUrl}/users/files/${newFileName}`;
this.updateRefProfilePic(url, logedUserData);
}
else {
throw new BadRequestException("Tipo de arquivo não suportado");
}
}