I'm trying to upload media files to Google Drive using the REST API and service account. I have a Cloud Functions backend where I authenticate with the right scopes for Google DRIVE API and return the access token (shown in the snippet below) to the client which could then make an upload request to Google Drive.
const auth = new google.auth.GoogleAuth({
scopes: [
'https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/drive.appdata',
'https://www.googleapis.com/auth/drive'
]
});
const client = await auth.getClient();
return await client.getAccessToken();
This works fine on the web as seen here and even on expo-snack-web as seen here. Now, I need to get this to work on the mobile platform, using React Native, but every time I upload a file, I get a 200 response and the file id, but I don't find the file on the specified folder or anywhere else on Google Drive. The snippet below is just a rewrite of the same logic I'm using to upload on the web version.
import React, {useEffect, useState} from 'react'
import {View, Text, StyleSheet, Platform, Button, Image} from 'react-native'
import * as ImagePicker from 'expo-image-picker';
import axios from 'axios'
import {decode as atob} from 'base-64'
export const UploadToDrive = (props) => {
const [image, setImage] = useState(null);
const [uploadPercent, setUploadPercent] = useState(0)
const [mimeType, setMimeType] = useState('')
useEffect(() => {
(async () => {
if (Platform.OS !== 'web') {
const { status } = await ImagePicker.requestCameraRollPermissionsAsync();
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!');
}
}
})();
}, []);
const pickImage = async () => {
const baseURL = 'https://dummy-server-address/api';
// Simultaneously get the access token while picking the media
const [{response}, result] = await Promise.all([
fetch(
`${baseURL}/services/fetch-access-token`,
{
mode: "cors",
}
)
.then((res) => res.json())
.then((resp) => resp)
.catch((err) => console.log(err)),
ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
})
]).catch((err) => console.log(err))
// ensure that all needed parameters/fields are present
if (!result.cancelled && response.token) {
const accessToken = response.token
const uri = "file:///" + result.uri.split("file:/").join("");
setImage(uri);
const file = result
let filename = uri.split('/').pop();
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
file.name = filename;
file.type = type
file.uri = uri
console.log(file)
setMimeType(file.type)
// Upload the image using the fetch and FormData APIs
let formData = new FormData();
const metadata = {
name: file.name,
type: file.type || 'multipart/form-data',
parents: ["1yz6MUU0YfXz0rl7TObq-JOPCmC6sHKdQ"],
};
// construct the file metadata for the upload
formData.append(
"metadata",
new Blob([JSON.stringify(metadata)], { type: "application/json" })
);
// formData.append('file', { uri, name: filename, type });
formData.append('file', file);
const url =
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id";
// let uploadPercent;
const upload_res = await axios(url, {
method: "POST",
headers: {
Authorization: "Bearer " + accessToken,
},
data: formData,
onUploadProgress: (p) => {
setUploadPercent((p.loaded / p.total) * 100)
},
})
.catch(err => console.log({err}))
.finally(() => setUploadPercent(0));
console.log({ data: upload_res.data });
} else {
throw new Error('You do not have all the right variables to make an upload')
}
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
{!!uploadPercent && <Text style={styles.uploadPercent}>Upload Percent: {`${uploadPercent.toFixed(2)}%`}</Text>}
<Button style={styles.button} title="Pick a file" onPress={pickImage} />
{image && mimeType.includes('image') && <Image source={{ uri: image }} style={{ width: 200, height: 200, marginTop: 20 }} />}
</View>
)
}
const styles = StyleSheet.create({
button: {
position: 'absolute',
top: '10%'
},
uploadPercent: {
color: 'tomato',
fontSize: 15,
fontWeight: 'bold',
marginBottom: 20
}
})
Please, what could I be doing wrong?