It's been a joruney trying to get simple file uploads to an AWS S3 bucket working from my react native app built with expo.
Current problem: Upon attempting the upload, I get an error saying:
Failed to construct URL with https://[bucket name].s3.us-east-1.amazonaws.com [TypeError: Cannot read property 'decode' of undefined]
.
I had to install react-native-url-polyfill/auto
and import it in my App.js file to get past a previous URL error, as suggested here. I also had to do some funky configurations for babel and Metro due to this issue
My code (with styling and a bunch of other components stripped out to make it a little simpler):
import { View, Modal, Pressable, Text, TextInput, Image, Alert } from 'react-native';
import { useEffect, useContext, useState } from 'react';
import { Button, Icon } from '@rneui/themed';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import * as ImagePicker from 'expo-image-picker';
import { AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_REGION, S3_BUCKET } from '@env';
const Memories = () => {
const [modalVisible, setModalVisible] = useState(false);
const [permissionStatus, requestPermission] = ImagePicker.useCameraPermissions();
const client = new S3Client({
credentials: {
accessKeyId: AWS_ACCESS_KEY_ID,
secretAccessKey: AWS_SECRET_ACCESS_KEY,
},
region: S3_REGION,
});
const pickImage = async () => {
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.canceled) {
const awsData = await handleUpload(result.assets[0]).catch((err) => console.log(err));
console.log(awsData);
}
};
const handleUpload = async (pickerResult) => {
try {
const res = await fetch(pickerResult.uri);
const imgBlob = await res.blob();
const data = await client.send(
new PutObjectCommand({
ACL: 'public-read',
Bucket: S3_BUCKET,
Key: `usergen-${Date.now().toString()}`,
Body: imgBlob,
})
);
return Promise.resolve(data);
} catch (err) {
console.log(err);
return Promise.reject(err);
}
};
return (
<View>
<Modal
animationType='slide'
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<TextInput
multiline
placeholder='Body Text'
value={bodyText}
onChangeText={setBodyText}
style={styles.textInput}
/>
<View>
<Button style={styles.btnGroup} onPress={pickImage}>
Upload from Camera Roll
</Button>
</View>
<Pressable
style={[styles.button, styles.buttonClose]}
onPress={() => setModalVisible(!modalVisible)}>
<Text style={styles.textStyle}>Cancel</Text>
</Pressable>
</View>
</View>
</Modal>
<Button
onPress={() => setModalVisible(!modalVisible)}>
<Icon type='ionicons' name='add' color='white' />
</Button>
</View>
);
};
export default Memories;
As I mentioned, this results in the following console output immediately after completing the image pick process:
Failed to construct URL with https://[bucket name].s3.us-east-1.amazonaws.com [TypeError: Cannot read property 'decode' of undefined]
LOG [TypeError: Cannot read property 'decode' of undefined]
LOG [TypeError: Cannot read property 'decode' of undefined]
LOG undefined
Any help, insights, resources, etc. would be greatly appreciated. This is my first time working with AWS in general. Has not been easy.