I am using GooglePicker with React, and the result I am getting is an array of objects...
[
{
"id": "1...m",
"serviceId": "docs",
"mimeType": "image/jpeg",
"name": "name.jpg",
"description": "",
"type": "photo",
"lastEditedUtc": 1575388407136,
"iconUrl": "https://drive-thirdparty.googleusercontent.com/16/type/image/jpeg",
"url": "https://drive.google.com/file/d/1...m/view?usp=drive_web",
"embedUrl": "https://drive.google.com/file/d/1...m/preview?usp=drive_web",
"sizeBytes": 111364,
"rotation": 0,
"rotationDegree": 0,
"parentId": "0...A"
}]
So I tried to access through https://www.googleapis.com/drive/v3/files
and directly through file.url
using
const fetchOptions = { headers: { Authorization: `Bearer ${accessToken}` } };
docs.forEach((file) => {
...
fetch(file.url, fetchOptions).then((res) => {
const blob = res.blob();
uploadFile(blob);
});
});
But I get 403
or CORS
; I tried setting the relayUrl
in the picker, but this broke the Picker.
Notes:
['https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.readonly']```
Any ideas?
Edit 1:
I also tried using Google API like this:
const FILE_URL = 'https://www.googleapis.com/drive/v3/files';
const url = isDoc
? `${FILE_URL}/${file.id}/export?mimeType=${mimeType}`
: `${FILE_URL}/${file.id}?alt=media`;
fetch(url, fetchOptions).then((res) => {
const blob = res.blob();
uploadFile(blob);
});
From your question it seems that you are trying to do everything with Google Picker. However, the picker will only get you limited metadata for the files, so you can open them with your account (i.e. see them in another window) or let you upload files. If you want to download the actual file, then you will need to use the Drive API.
Drive Quickstart for browser JavaScript
The flow might be:
get
with alt='media'
)If I have misunderstood and you are already using the Drive API, then it would be helpful to see the associated code with that.
Here is an example of using the Picker API to feed into the Drive API with gapi
using the same login client.
HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Google Picker Example</title>
</head>
<body>
<button id="authorize_button" style="display: none;">Authorize</button>
<button id="signout_button" style="display: none;">Sign Out</button>
<div id="result"></div>
<script type="text/javascript" src="script.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body>
</html>
JS
const API_KEY = 'AI...';
const CLIENT_ID = '44...';
const appId = "44...";
const SCOPES = ["https://www.googleapis.com/auth/drive"];
const DISCOVERY_DOCS = [
"https://www.googleapis.com/discovery/v1/apis/drive/v3/rest",
];
const authorizeButton = document.getElementById("authorize_button");
const signoutButton = document.getElementById("signout_button");
// Use the Google API Loader script to load the google.picker script.
function handleClientLoad() {
gapi.load("client:auth2:picker", initClient);
}
function initClient() {
gapi.client.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES[0]
})
.then(
function () {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(handleSignIn);
// Handle the initial sign-in state.
handleSignIn(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
},
function (error) {
appendPre(JSON.stringify(error, null, 2));
}
);
}
function handleSignIn(isSignedIn) {
if (isSignedIn) {
authorizeButton.style.display = "none";
signoutButton.style.display = "block";
createPicker();
} else {
authorizeButton.style.display = "block";
signoutButton.style.display = "none";
}
}
function handleAuthClick(event) {
gapi.auth2.getAuthInstance().signIn();
}
function handleSignoutClick(event) {
gapi.auth2.getAuthInstance().signOut();
}
function createPicker() {
const token = gapi.client.getToken().access_token
if (token) {
let view = new google.picker.View(google.picker.ViewId.DOCS);
view.setMimeTypes("image/png,image/jpeg,image/jpg");
let picker = new google.picker.PickerBuilder()
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.setAppId(appId)
.setOAuthToken(token)
.addView(view)
.addView(new google.picker.DocsUploadView())
.setDeveloperKey(API_KEY)
.setCallback(getFile)
.build();
picker.setVisible(true);
}
}
function getFile(pickerResp) {
gapi.client.drive.files
.get({
fileId: pickerResp.docs[0].id,
alt: 'media'
})
.then(resp => {
console.log("fetch response", resp.status)
let binary = resp.body
// EDIT - addition from Gabrielle vvvv
let l = binary.length
let array = new Uint8Array(l);
for (var i = 0; i<l; i++){
array[i] = binary,charCodeAt(i);
}
let blob = new Blob([array], {type: 'application/octet-stream'});
// EDIT - addition from Gabrielle ^^^^
}
This code is adapted from the Drive Quickstart and the Picker Quickstart.
Note - this does give an error in the console, but it does seem to work all the same. This does seem to be a bug with the Picker - https://issuetracker.google.com/177046274
EDIT from Gabrielle
Note - using get with alt = media
is for binary files. To get sheets/docs/slides etc, you need to use the export
end point.