The Google Drive API for the very, very beginner.
Tags: googlecloud, api, tutorial, beginners
Published: 2022-07-12 00:52:23

An easy to understand guide on how to use the [Google Drive API][1]

---

## Table of contents
<!--ts-->
   * [What its used for](#what-its-used-for)
   * [Types of Authentication](#types-of-authentication)
      * [API key](#api-key)
      * [OAuth client ID](#oauth-client-id)
      * [Service account](#service-account)
   * [Authenticating our Application](#authenticating-our-application)
      * [Using API key](#using-api-key)
      * [Using Google OAuth client ID](#using-google-oauth-client-id)
      * [Using Service account](#using-service-account)
  * [Sending a request](#sending-request)
    * [Using the API key](#using-the-api-key) 
    * [Using the OAuth client ID](#using-the-oauth-client-id)
  * [File Methods, examples:](#file-methods-examples)
    * [set root Url](#set-root-url)
    * [copy](#copy)
    * [create](#create)
      * [create a new folder](#create-a-new-folder)
      * [Upload a new file](#upload-a-new-file)
    * [delete](#delete)
    * [empty trash](#empty-trash)
    * [export](#export)
    * [generateIds](#generateids)
    * [get](#get)
    * [list](#list)
    * [update](#update)
    * [watch](#watch)
    * [stop](#stop)

<!--ts-->

## What its used for

In simple words: it help us to send HTTP requests in a way that the Google servers can accept, allowing us to manipulate the the Google Drive files.

## Types of Authentication

The first step is to decide the authentication method, here are the option and use cases:

* ### API key
  Use this credential to access/get publicly-available data anonymously, this means files set as "[anyone with the link][2]", you can't set/insert data just read it. you can safely expose this key to the user, since you can control the request via Google Cloud Platform.

* ### OAuth client ID
  Use this credential to authenticate as an end user and access their data. Requires your app to request and receive consent from the user via OAuth, this requires a server in the middle to handle the keys, since this can't be expose to the end user.

* ### Service account
  Use this credential to authenticate as a service account or to access files on behalf of Google Workspace. This service accounts can't be accessed using a username or password, you must be careful with the keys since it can compromise your Google Account.

## How to Get the keys:

  * API key
    ---------

    Go to https://console.cloud.google.com/apis/credentials > Create Credentials > API Key
  
    !Alert: This API key is normally exposed to the public, so you may want to restrict the API, because its usage will count towards your account.
 
  * OAuth client ID
    ---------------
    Go to https://console.cloud.google.com/apis/credentials > Create Credentials > OAuth client ID
 
  * Service Accounts
    ----------------
    Go to https://console.cloud.google.com/apis/credentials > Create Credentials > Service account

## Authenticating our Application

### Using API key

```js 
const { google } = require('googleapis');

const API_KEY = 'RanD0mK3Y-abcdevwefw-1234567890';

async function main() {
    const drive = google.drive({ version: 'v3', auth: API_KEY });
    console.log(drive);
}
```

### Using Google OAuth client ID
```js
const { google } = require('googleapis');
const fs = require('fs');
const readline = require('readline');
const SCOPES = ['https://www.googleapis.com/auth/drive']; // Allows all scopes 
const TOKEN_PATH = './token.json'; // If this file doesn't exist, will be created later.
const CREDENTIALS_PATH = './client_secret_1234567890.json' // replace name with your secret file
let credentials, token;
// Getting credentials
try {
    const file = await fs.promises.readFile(CREDENTIALS_PATH);
    credentials = JSON.parse(file);
} catch (err) {
    console.error('Unable to read file:', err);
}
const { installed: { client_id, client_secret, redirect_uris } } = credential;
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
// Getting Token
try {
    const file = await fs.promises.readFile(TOKEN_PATH);
    token = JSON.parse(file);
} catch (err) {
    const authUrl = oAuth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: SCOPES,
    });
    console.log('Authorize this app by visiting this url:', authUrl);
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
    });
    rl.question('Enter the code from that page here: ', (code) => {
        rl.close();
        oAuth2Client.getToken(code, async (err, r_token) => {
            if (err) reject(err);
            await fs.promises.writeFile(TOKEN_PATH, JSON.stringify(r_token), (err) => {
                if (err) reject(err);
                console.log('Token stored to', `./${TOKEN_PATH}`);
            });
            token = r_token;
        });
    });
}
// Setting token 
oAuth2Client.setCredentials(token);
const drive = google.drive({ version: 'v3', auth: oAuth2Client });
```

### Using Service account
```js
const { google } = require('googleapis');
const path = require('path');

const KEYFILEPATH = path.join(__dirname, 'service.json');
const SCOPES = ['https://www.googleapis.com/auth/drive'];

const auth = new google.auth.GoogleAuth({
    keyFile: KEYFILEPATH,
    scopes: SCOPES,
});
const drive = google.drive({ version: 'v3', auth });
```
## Sending a request

Regardless of the method or programming language we use, the HTTP request that Google will receive, looks like this:

- Using the API key
```http
GET /drive/v3/files/AbCdEFGhijklmopr-abcde_fghijl-oqQrstuvWxyZ?fields=kind%2C%20id%2C%20name&key=Abcdefghij-KmnloprstuVwxyZ HTTP/1.1
Host: googleapis.com
User-Agent: google-api-nodejs-client/0.7.2 (gzip)
Accept: application/json
Accept-Encoding: gzip
X-Forwarded-For: 190.191.192.193
X-Forwarded-Proto: https
```
- Using the OAuth client ID
```http
GET /drive/v3/files/17qEQsVNm-XWtdGSWy2_p0-pyoLaZS0mq16L1mKX2it4?fields=kind%2C%20id%2C%20name HTTP/1.1
Host: googleapis.com 
User-Agent: google-api-nodejs-client/0.7.2 (gzip)
Accept: application/json
Accept-Encoding: gzip
Authorization: Bearer ya12.RaNdOmStRinG1234RaNdOmStRinG1234RaNdOmStRinG1234-RaNdOmStRinG1234_RaNdOmStRinG1234_RaNdOmStRinG1234
X-Forwarded-For: 190.191.192.193
X-Forwarded-Proto: https
```
Sending the same request with the [Google APIs Node.js Client][3] package will look like this:
```js
// The authentication was done using the previous methods
const path_parameters = {
    fileId: 'AbCdEFGhijklmopr-abcde_fghijl-oqQrstuvWxyZ',
    fields: 'kind, id, name',
}
const result = await drive.files.get(path_parameters, options);
```

## File Methods, examples:

## set root Url 
You can send the HTTP request to a different server, for example you can send the request to a [ngrok https server tunneling ncat][4] to output all the incoming requests, this can be useful if you want to see what exactly is receiving the server.
```js
const options = {
    rootUrl: 'https://www.googleapis.com',
}
// const options = {
//     rootUrl: 'https://1234-199-199-199-199.ngrok.io/'
// }
```
## copy
```js
const parents = ['YOUR_PARENT_ID_IN_ARRAY'];
const fileId = 'YOUR_ID_OF_THE_FILE_TO_BE_COPIED';
const name = 'YOUR_NEW_NAME';
const path_parameters = {
    fileId: fileId,
    fields: 'kind, id, name',
    resource: {
        name: name,
        parents: parents,
    },
}
const result = await drive.files.copy(path_parameters, options);
```
## create
  - create a new folder
```js
const parents = ['YOUR_PARENT_FOLDER_OPTIONAL'];
const name = 'YOUR_NEW_FOLDER_NAME';
const path_parameters = {
    resource: {
        name: name, 
        mimeType: 'application/vnd.google-apps.folder',
        parents: parents,
    },
    fields: 'kind, id, name',
}
const result = await drive.files.create(path_parameters, options);
```
 - Upload a new file
```js
const path_parameters = {
    resource: {
        name: 'YOUR_NEW_FILE_NAME',
        parents: ['YOUR_PARENTS_IDs_OPTIONAL'],
    },
    media: {
        body: 'YOUR_READABLE_STREAM',
    },
    fields: 'kind, id, name',
}

const result = await drive.files.create(path_parameters, options);
```
## delete
```js
const path_parameters = {
    fileId: 'YOUR_FILE_ID',
    fields: 'kind, id, name',
}
const result = await drive.files.delete(path_parameters, options);
```
## empty trash
```js
await drive.files.emptyTrash({});
```

## export
For a list of avaiable mimeTypes available visit this [link][6] 
```js
const path_parameters = {
    fileId: 'YOUR_FILE_ID',
    mimeType: 'THE MIMETYPE',
    fields: 'kind, id, name',
}
const options = {
    responseType: 'stream',
    rootUrl: 'https://www.googleapis.com',
}
const result = await drive.files.export(path_parameters, options);
```

## generateIds
```js
const fields = 'kind, space, ids';
const path_parameters = {
    count: 3, // the number of IDs you want
    fields: fields,
}
const result = await drive.files.generateIds(path_parameters, options);
```
## get
```js
const path_parameters = {
    fileId: 'YOUR_FILE_ID',
    fields: 'kind, id, name',
}
const result = await drive.files.get(path_parameters, options);
```
## list
For a list of query string parameters visit this [link][5]
```js
const fields = "kind, nextPageToken ,files(kind, id, name)";
const query = "YOUR_QUERIES";
const nextPageToken = "TO_CONTINUE_WITH_A_PREVIOUS_LIST";
const path_parameters = {
    q: query,
    pageSize: 5, // Number of files returned
    fields: fields,
    pageToken: nextPageToken, // optional
}
const listFiles = await drive.files.list(path_parameters, options);
```
## update
```js
const path_parameters = {
    fileId: "YOUR_FILE_ID",
    fields: 'kind, id, name',
    resource: {
        trashed: true, // This will send the file to trash
        name: 'YOUR_NEW_FILE_NAME'
    },
}
const result = await drive.files.update(path_parameters, options);
```
## watch
This will send a HTTP request to the address every time the file is modified
```js
// use https://github.com/uuidjs/uuid to generate a unique id
const channelId = "01234567-89ab-cdef-0123456789ab";
const path_parameters = {
    fileId: 'THE_ID_OF_THE_FILE_YOU_WANT_TO_WATCH',
    supportsAllDrives: true,
    supportsTeamDrives: true,
    requestBody: {
        id: channelId,
        type: "web_hook",
        address: "https://example.com/webhook",
        payload: true,
    },
}
const result = await drive.files.watch(path_parameters, options);
```
## stop
This will stop or unwatches the  provious watch file
```js 
const channelId = "01234567-89ab-cdef-0123456789ab";
const path_parameters = {
    requestBody: {
        id: channelId,
        // The watch function returns this value
        resourceId: 'abcdeF-GHIJKLMNOPQRSTUVW',
    },
}
const result = await drive.channels.stop(path_parameters, options);
```
Check my repo for the code [github.com/FredySandoval/google-drive-api-usage-examples][7]

[1]: https://developers.google.com/drive/api/
[2]: https://support.google.com/drive/answer/2494822?hl=en&co=GENIE.Platform%3DDesktop#zippy=%2Cshare-a-file-publicly
[3]: https://github.com/googleapis/google-api-nodejs-client
[4]: https://gist.github.com/FredySandoval/ff34e87f83e4c4dc4a771df44fc7e31c
[5]: https://developers.google.com/drive/api/guides/search-files
[6]: https://developers.google.com/drive/api/guides/ref-export-formats
[7]: https://github.com/FredySandoval/google-drive-api-usage-examples