How to save image from web URL to Google Drive using JavaScript API

I’m working with JavaScript and Google Drive API but stuck on one part. I can authenticate and make directories fine, but I can’t figure out how to grab an image from a web URL and save it to my Drive.

Here’s my working code that makes a new directory:

function makeNewDirectory(dirName) {
  var targetParent = 'yyyyyyy'; // parent directory ID
  var folderData = {
    'name': dirName,
    'mimeType': 'application/vnd.google-apps.folder',
    'parents': [targetParent]
  };
  gapi.client.drive.files.create({
    resource: folderData,
  }).then(function(result) {
    if(result.status === 200) {
      var newFolder = result.result;
      console.log('New Directory ID: ', newFolder.id);
      saveImageFile(newFolder.id);
    } else {
      console.log('Failed to create directory: ' + result);
    }
  });
}

I need to download an image from https://example-site.com/image.png and put it in the new directory. The Google docs show this example but it reads from local files:

function saveImageFile(parentDir) {
  var imageData = {
    'name': 'picture.jpg',
    parents: [parentDir]
  };
  var uploadMedia = {
    mimeType: 'image/jpeg',
    body: fs.createReadStream('local/picture.jpg')
  };
  drive.files.create({
    resource: imageData,
    media: uploadMedia,
    fields: 'id'
  }, function (error, result) {
    if (error) {
      console.error(error);
    } else {
      console.log('Uploaded File ID: ', result.id);
    }
  });
}

How do I modify this to fetch from a web URL instead of a local file path?

XMLHttpRequest with arraybuffer response type works way better than blob for Drive API uploads. I’ve hit the same issues and this approach is much more stable:

function saveImageFile(parentDir, imageUrl) {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', imageUrl);
  xhr.responseType = 'arraybuffer';
  
  xhr.onload = function() {
    if (xhr.status === 200) {
      const imageData = {
        'name': 'downloaded-image.png',
        'parents': [parentDir]
      };
      
      gapi.client.request({
        'path': 'https://www.googleapis.com/upload/drive/v3/files',
        'method': 'POST',
        'params': {'uploadType': 'media'},
        'headers': {'Content-Type': 'image/png'},
        'body': xhr.response
      }).then(result => {
        console.log('Image saved:', result.result.id);
      });
    }
  };
  
  xhr.send();
}

Arraybuffer skips the encoding problems I ran into with blob conversions. Just watch out for CORS - the image URL needs to allow cross-origin requests or you’ll get blocked.

xhr works better than fetch for CORS issues. Set responseType to ‘blob’ and pass it straight to the gapi client create method. Way more reliable than multipart in my experience.

First fetch the image from the URL, then upload that blob to Google Drive. Don’t use fs.createReadStream - use fetch to get the image data and convert it to a blob. Here’s what worked for me:

function saveImageFile(parentDir, imageUrl) {
fetch(imageUrl)
.then(response => response.blob())
.then(blob => {
const metadata = {
‘name’: ‘picture.png’,
‘parents’: [parentDir]
};

  const form = new FormData();
  form.append('metadata', new Blob([JSON.stringify(metadata)], {type: 'application/json'}));
  form.append('file', blob);
  
  return fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', {
    method: 'POST',
    headers: new Headers({'Authorization': 'Bearer ' + gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse().access_token}),
    body: form
  });
})
.then(response => response.json())
.then(result => {
  console.log('File uploaded:', result.id);
})
.catch(error => console.error('Upload failed:', error));

}

Basically, fetch the image as a blob first, then use the multipart upload endpoint with FormData instead of the client library’s create method.

This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.