How to upload a file to Google Drive using Node-RED

For a home automation project I needed to upload files to Google Drive v3. I use Node-RED together with Home assistant for adding “intelligence” to my home automation. My HP printer has a feature to scan documents to email. I wanted to use this feature to scan documents and automatically upload them as PDF to Google Drive. Within Node-RED the http request node is the obvious choice to accomplish this, but I found it challenging to get it uploading multipart-encoded payloads.

In this post I will show you how to use the Node-RED http request node to upload a file to Google Drive using the v3 API, using a multipart-encoded payload.

Google Drive v3 API

The Google Drive v3 API is a REST API that allows you to interact with Google Drive. It is a very powerful API that allows you to do a lot of things. The API is documented here in general and uploading files is documented in more detail here.

Prerequisites

Apart from having some experience with Node-RED already, you need to ensure that you have followed the OAuth 2.0 authorization guide to create a client ID and client secret for your application. You can found more about that here. For this file create functionality I used the “Desktop app” option and the following scopes:

https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/drive.metadata

I found this YouTube video to be very helpful in setting up the OAuth 2.0 authorization part.

When you have the Bearer token you can use the API to upload files to Google Drive, but because it expires after 1 hour you need to refresh it. I’ve implemented this manually in Node-RED, but you can also use the node-red-contrib-google-oauth2 extension to do this for you.

Node-RED http request node

So this is where the upload magic happens. For the Node-RED http request node I used the following javascript block in the On Message tab to set the method, headers, payload and url for the request:

var payload = msg.payload // make sure you set the (binary) payload here
var token = // make sure you set the token here (without the Bearer prefix)
var scan_filename = // make sure you set the filename here, e.g. "scan.pdf"
var folder_id = // make sure you set the folder id here. If you omit it and remove it from the variable below, the file will be placed in the root of your Google drive.
var metadata_json_encoded = '{"name": "' + scan_filename + '", "parents": ["' + folder_id + '"]}';

msg.method = "POST";
msg.headers = {
        "Authorization": "Bearer " + token,
        "Content-Type": "multipart/form-data"
    }
msg.payload = {
    "json": {
        "value": metadata_json_encoded,
        "options": {
            "contentType": 'application/json; charset=UTF-8',
        }
    },
    "file": {
        "value": payload,
        "options": {
            "filename": scan_filename,
            "contentType": 'application/pdf; charset=UTF-8',
        }
    }
}
msg.url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
return msg;

Conclusion

Now I can use my HP printer to scan documents and have them uploaded to my personal Google Drive, also allowing me to share them with others because of the Google Drive sharing functionality.