Samarth Bagga
Samarth Bagga

Reputation: 41

Unable to upload images to Digital Ocean spaces through Expo and AWS SDK

I am trying to upload an image to my DigitalOcean Spaces using the Expo Image Picker and AWS SDK, but I keep encountering this error:

ERROR  Error uploading image: [TypeError: Network request failed]

Here’s the relevant code that I’m using to upload the image:

import AsyncStorage from '@react-native-async-storage/async-storage';
import axios from 'axios';
import * as ImagePicker from 'expo-image-picker';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import 'react-native-get-random-values'; // This polyfills crypto.getRandomValues
import { v4 as uuidv4 } from 'uuid';
import { spaces } from '../config/digitalOcean';
import 'react-native-url-polyfill/auto';
import { ReadableStream } from 'web-streams-polyfill';
globalThis.ReadableStream = ReadableStream;

export default function AddItems({ navigation }) {
  const [produceName, setProduceName] = useState('');
  const [quantity, setQuantity] = useState('');
  const [price, setPrice] = useState('');
  const [itemImage, setItemImage] = useState('');
  const [phoneNumber, setPhoneNumber] = useState('');
  const [uploading, setUploading] = useState(false);

  const s3Client = new S3Client({
    endpoint: spaces.url,
    forcePathStyle: false,
    region: "blr1",
    credentials: {
      accessKeyId: spaces.spacesKey,
      secretAccessKey: spaces.spacesSecret
    }
  });

  useEffect(() => {
    const loadPhoneNumber = async () => {
      try {
        const storedPhoneNumber = await AsyncStorage.getItem('phone');
        if (storedPhoneNumber) {
          setPhoneNumber(storedPhoneNumber);
        } else {
          Alert.alert('Error', 'Phone number not found');
        }
      } catch (error) {
        console.error('Error loading phone number from AsyncStorage:', error);
      }
    };

    loadPhoneNumber();
  }, []);

  const pickImageAsync = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      allowsEditing: true,
      quality: 1,
    });

    if (!result.canceled) {
      uploadImage(result.assets[0]);
    } else {
      alert('You did not select any image.');
    }
  };

  const getImageBlob = (uri) => {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.onload = function() {
        resolve(xhr.response);
      };
      xhr.onerror = function() {
        reject(new Error('XMLHttpRequest failed'));
      };
      xhr.responseType = 'blob';
      xhr.open('GET', uri, true);
      xhr.send(null);
    });
  };

  const uploadImage = async (imageAsset) => {
    setUploading(true);
    const fileName = `${uuidv4()}.jpg`;

    try {
      const response = await fetch(imageAsset.uri);
      const blob = await getImageBlob(imageAsset.uri);
      console.log("these happened without error");
      console.log(response);
      console.log(blob);

      const params = {
        Bucket: spaces.name,
        Key: fileName,
        Body: blob,
        ACL: "public-read",
        ContentType: 'multipart/form-data',
      };

      const data = await s3Client.send(new PutObjectCommand(params));
      console.log(data);

      const imageUrl = spaces.url + "/" + fileName;
      setItemImage(imageUrl);
      Alert.alert('Success', 'Image uploaded successfully');
    } catch (error) {
      console.error('Error uploading image:', error);
      Alert.alert('Error', 'Failed to upload image');
    }
    setUploading(false);
  };

  const handleSubmit = async () => {
    if (!produceName || !quantity || !price) {
      Alert.alert('Error', 'All fields are required');
      return;
    }

    try {
      const formData = {
        phoneNumber,
        itemName: produceName,
        quantity,
        price,
        itemImage,
      };

      const response = await axios.post(
        'myurl/api/supplier/add-item',
        formData
      );

      if (response.status === 200) {
        Alert.alert('Success', 'Item added successfully!');
        navigation.goBack();
      }
    } catch (error) {
      console.error('Error adding item:', error.response?.data || error.message);
      Alert.alert(
        'Error',
        error.response?.data?.message || 'Failed to add item, please try again'
      );
    }
  };

I've tried the following but haven't found a solution yet:

  1. Ensured that I have valid credentials for DigitalOcean Spaces.
  2. Double-checked the spaces.url, accessKeyId, and secretAccessKey to ensure they're correct.

What could be causing this Network request failed error when trying to upload the image? Is there something wrong with how I'm handling the image blob or the AWS S3 configuration?

Upvotes: 0

Views: 96

Answers (1)

Faisal Nawaz
Faisal Nawaz

Reputation: 47

try creating blob like this with fetch and make sure cors policy on DigitalOcean space has included put and post in AllowedMethods.

const getImageBlob = async (uri) => {
  const response = await fetch(uri);
  const blob = await response.blob();
  return blob;
};

Upvotes: 0

Related Questions