How Can I do a Post request sending a photo into body of type binary in React Native? - react-native

I'm using React Native and I need to send an image in base64 format using a POST method of binary type.
const session = await Auth.currentSession();
const config = {
headers: {
"Content-Type": "image/jpeg",
"x-amz-acl": "public-read",
Authorization: session.getIdToken().getJwtToken(),
},
};
const API = `event/${eventData.id}/photos`;
const HOST = "https://host.com/";
const url = `${HOST}/${API}`;
const result = await axios.post(url, photo.uri, config);
console.log("Result: ", result);
But I'm running into this error: [AxiosError: Request failed with status code 400]
My postman:
I'm trying to get the right response data from AWS S3.

Related

Send binary data as file to API using Expo

I would like to know if there is any way to send binary data that is not an image or a video in Expo to an API expecting a file as part of the FormData received.
The API expects binary data so I cannot allow myself to convert it to base64 like people advice to do.
This is what I use today, the server does not recognize a file field.
const form = new FormData();
form.append('url', downloadurl);
form.append('pageUrl', payload.link);
form.append('name', payload.name);
form.append('file', new Blob([buffer]), 'file');
const res = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: form,
});
EDIT
The following snippet seems to send the blob to the backend. However, the blob size is nearly double the size of the array, which results in the file being received corrupted.
const blob = new Blob([buffer.raw], {
type: 'application/octet-stream',
});
// Here it logs blob with 47000 size, 25330, 25330
console.log(blob, buffer.raw.length, buffer.raw.byteLength);
const url = URL.createObjectURL(blob);
const file = {
uri: url,
type: 'application/octet-stream',
name: 'torrent',
};
const formData = new FormData();
formData.append('torrent', file as any);
formData.append('url', downloadurl);
formData.append('pageUrl', payload.link);
formData.append('name', payload.name);
const xhr = new XMLHttpRequest();
xhr.open('POST', endpoint);
xhr.onload = () => {
console.log('DONE', xhr.status);
};
xhr.send(formData);

how to upload images using Zendesk Upload API

I'm using the function below to upload images on zendesk. Zendesk requires image to be in binary to be uploaded and getting the blob image method is working when I'm uploading on Firebase. These function gets a response 201 but when you check the image, is just a white square. I think image got corrupted during the upload.
imageUri is returned from expo-image-picker like this below:
file:/data/user/0/host.exp.exponent/cache/ExperienceData/.../ImagePicker/8543faa5-b996-46cd-9554-ce9afb61385b.jpg
const uploadImages = async (imageUri) => {
try {
const filename = getFilenameFromImagePicker(imageUri);
const resImg = await fetch(imageUri);
const blobImg = await resImg.blob();
const response = await axios.post(`uploads?filename=${filename}`, {
blobImg
}, {
auth: {
username: membersEmail + '/token',
password: ZENDESK_API_KEY
},
headers: {
'Content-Type': 'application/binary',
}
})
return response.data;
}
catch (error) {
captureException(error);
return null;
}
}
What is the best way to change the image to binary so it can be uploaded to zendesk?
Below is the curl statement from Zendesk's documentation for uploading images
curl "https://{subdomain}.zendesk.com/api/v2/uploads?filename=myfile.dat&token={optional_token}" \
-data-binary #file.dat \
-v -u {email_address}:{password} \
-H "Content-Type: application/binary" \
-X POST
This is my typescript solution and it works.
file is file from
static uploadVideo = async (file:any) => {
// first get our hands on the local file
const localFile = await fetch(URL.createObjectURL(file));
// then create a blob out of it
const fileBlob = await localFile.blob();
const url = `${YOUR_URL}/v2/uploads?filename=${file?.name}`
return await axios({
method: "POST",
url: url,
data: fileBlob,
headers: {'Content-Type': 'application/binary'}
})
}
After alot of testing, I was able to make it work. Posting here the answer I come up with incase someone else has the same problem.
async function uploadImages (imageUri) {
// first get our hands on the local file
const localFile = await fetch(imageUri);
// then create a blob out of it (only works with RN 0.54 and above)
const fileBlob = await localFile.blob();
// then send this blob to filestack
const serverRes = await fetch('https://www.yourAwesomeServer.com/api/send/file', { // Your POST endpoint
method: 'POST',
headers: {
'Content-Type': application/binary,
},
body: fileBlob, // This is your file object
});
const serverJsonResponse = await serverRes.json();
return serverJsonResponse;
}

React Native uploading file to multer, i am getting empty buffer

I am making an App with React Native and back end with NodeJS. From VueJS it is exactly the same code(except i am getting the file from an input), and its working fine from an Input and Postman, but i am having trouble on React Native
Code in the App:
const formdata = new FormData()
const file = myMainImage
console.log(file)
const fileName = file.split("/").reverse()[0];
formdata.append('media', {
url: file,
name: fileName,
type: 'image/jpeg'
})
await profileApi.uploadMyMainImage(formdata)
And the request to the backend (tried with axios and fetch)
const postFormMethodWithAuthorization = async (url, content) => {
const headers = getHeaderWithAuthorizationForm()
const response = await Axios.post(url, content, {headers} )
return response.data
}
const postFileusingFetch = async (url, content) => {
const result = await fetch(url, {
method: 'POST',
headers: new Header(await getHeaderWithAuthorizationForm()),
body: content
})
return await result.json()
}
but in the back end i am always getting from req.file:
{
fieldname: 'media',
originalname: 'DADE2091-0C50-456B-8F89-408CCAD98E02.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
buffer: <Buffer >,
size: 0
}
Any Ideas? i thought it can be something related to the file being upload, so i treated it like a stream, but same problem happens, also i am uploading it into AWS S3, but when i get it back the file is empty and cant be opened.
The image uri is being taken from the Camera. I also tried removing file:// with no luck.
Any Help appreciated!

Network Error when sending file in react native with axios

I am trying to send a file to a nodejs server from react native using axios, this is my code:
const createFormData = (file) => {
const data = new FormData();
data.append('message', text);
data.append('receiver',doctorid);
if(file !== ''){
data.append('file', {
type: file.type,
uri: file.uri,
name: file.name.replace(/\s/g,'')
})
}
return data;
}
const onSend = async() => {
const newMessages = [...messages]
newMessages.push({"sender": currentuserID, "id": 339, "message": 'sending...', "attachment": '', "receiver": doctorid, "type": 0},)
setMessages(newMessages)
const token = await AsyncStorage.getItem('token');
const data = createFormData(singleFile)
await appApi.post('/chats', data, {
headers: { 'Authorization': 'Bearer ' + token }
}).then(()=>{
socket.emit('sendmessage', text, (err) => {
messageInit()
});
})
.catch(err => console.log(err.message))
}
This code works perfectly if there's no image attached, but ones there's an image attached, I get the network error message immediately.
For a little bit of troubleshooting, I tried sending request to my local machine, using ngrok. From ngrok, I realized the request wasn't sent at all to the url. So it just fails immediately, without the request been made to the url.
Anyone with solution to this.
I'm testing on an android emulator
send using formdata
try this
let formData = new FormData();
let imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})

Presigned URL image upload with Google Cloud Storage does not upload image correctly (MERN + React Native)

I am able to generate signedUrls from my server and send it back to my React Native (expo) client.
The client is also able to send a put request to the signedUrl with an image object that includes a uri to an image stored on the device.
The problem is that the image saved in Google Cloud appears corrupt. I imagine there must be additional settings I need to add to get the image to upload properly.
Server Code To Generate URL
const { Storage } = require("#google-cloud/storage");
const storage = new Storage({keyFilename: "keys.json"});
const bucketName = "bucket";
const bucket = storage.bucket(bucketName);
const { v4 } = require("uuid");
async upload(req, res, next) {
const options = {
action: "write",
expires: Date.now() + 15 * 60 * 1000, // 15 minutes,
contentType: "image/jpeg"
};
const fileName = `1234/${v4()}.jpg`
const [url] = await bucket.file(fileName).getSignedUrl(options);
res.send(url)
}
Example of presigned URL from server
const url = "https://storage.googleapis.com/bucket/1234/00bae114-87e4-4647-94d3-31115453e9bd.jpg?GoogleAccessId=id%40num.iam.gserviceaccount.com&Expires=1587297408&Signature=signaturecode"
Example of an image object
const image = {
"name": "IMG_4831.JPG",
"type": "image/jpeg",
"uri": "assets-library://asset/asset.JPG?id=AC24211D-E728-44D2-8B00-29EF04EC74E0&ext=JPG"
}
React Native code to send image through presigned URL
import axios from "axios";
const image = {uri, type: "image/jpeg", name };
await axios.put(url, image, {
headers: { "Content-Type": "image/jpeg" }
});
I tried to use expo FileSystem.uploadAsync(url, fileUri, options) instead of axios and it works.