0

I am using Expo Image Picker to select an image from the gallery so I can upload the file to a Supabase storage bucket called 'avatars'. In the Supabase storage docs they say:

For React Native, using either Blob, File or FormData does not work as intended. Upload file using ArrayBuffer from base64 file data instead, see example below.

They also give this example:

import { decode } from 'base64-arraybuffer'

const { data, error } = await supabase
  .storage
  .from('avatars')
  .upload('public/avatar1.png', decode('base64FileData'), {
    contentType: 'image/png'
})

I thought to decode the base64 string of the Image Picker result and pass it in as Supabase's fileBody in upload.

In my code below I am getting the following error at the bucket uploading:

[StorageApiError: mime type text/plain;charset=UTF-8 is not supported]

 async function uploadAvatar(){
        try{
            if (!session?.user) throw new Error("No user on the session!")

            setUploading(true)

            const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync()

            if(!permissionResult.granted){
                Alert.alert('Permission required', 'Permission to access the media library is required.');
                return;
            }

            let result = await ImagePicker.launchImageLibraryAsync({
                //Default mediaType is images
                allowsEditing: true,
                aspect: [4, 3],
                quality: 1,
                base64: true,
            })

            // console.log(result)

            if(!result.canceled){
                const image = result.assets[0]
                const fileExt = image.fileName?.split('.').pop()
                const filePath = `${session?.user?.id as string}/avatar.${fileExt}`

                if(!image.base64){
                    throw new Error("Could not upload image.")
                }

                let {data : bucket_file, error: upload_error} = await supabase.storage
                    .from('avatars')
                    .upload(filePath, decode(image.base64), {upsert: true})

                if(upload_error){
                    console.log(upload_error)
                    throw upload_error
                } 

                const {data: profile, error: profile_error} = await supabase
                    .from("profiles")
                    .select("avatar_url")
                    .eq('user_id', session?.user?.id)
                    .single()

                if(profile_error){
                    throw(profile_error)
                }


                if(!profile?.avatar_url){
                    const {error: update_error} = await supabase
                        .from("profiles")
                        .update({
                            avatar_url: bucket_file?.path,
                            updated_at: new Date(),
                        })
                        .eq('user_id', session?.user?.id)

                    if(update_error){
                        throw(update_error)
                    }
                }

                const { error: tsError } = await supabase
                    .from("profiles")
                    .update({
                    updated_at: new Date()
                    })
                    .eq("user_id", session?.user?.id);

                if(tsError){
                    throw tsError
                };

            }
        } catch(error){
            if (error instanceof Error){
                Alert.alert(error.message)
            }
        } finally {
            setUploading(false)
        }
    }

I would very much appreciate your help, thank you!

1 Answer 1

0

Update: It turns out I was forgetting to specify the contentType in the fileOptions argument of the Supabase upload function.

For the contentType the Supabase docs say:

Should be specified if using a fileBody that is neither Blob nor File nor FormData, otherwise will default to text/plain;charset=UTF-8.

In Supabase bucket upload:

let {data : bucket_file, error: upload_error} = await supabase.storage
    .from('avatars')
    .upload(filePath, decode(image.base64), {
        contentType: photo.type, 
        upsert: true
    })
Sign up to request clarification or add additional context in comments.

1 Comment

If you need reference to different values for contentType you can check this: stackoverflow.com/a/48704300/17255655. In my case I just set it to 'image/jpeg'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.