#drive #google-api #google #v3 #api-bindings #api

macro drive-v3-macros

A library for interacting the Google Drive API

2 releases

0.6.1 Feb 23, 2024
0.6.0 Feb 19, 2024

#7 in #v3


Used in 2 crates (via drive-v3)

MIT license

76KB
1.5K SLoC

drive-v3

pipeline coverage

A Rust library to send request to the Google Drive API v3.

This library includes functions to call all Google Drive API v3 present in Google's documentation as of the date of the latest release.

Usage

Setup

Before using Google Drive's API you need to enable it on a Google Cloud project.

This is free and you can follow these steps to enable the API.

After you complete the Authorize credentials for a desktop application section, you can us the saved client_secrets.json file to authorize this library.

Getting credentials

Before you start making calls to Google's API, you first need to get some valid Credentials.

For this you will need your client_secrets.json file and the scopes that you plan on using. For help on selecting scopes you can read Google's choose scopes guide.

With these elements you can call Credentials::from_client_secrets_file to prompt you to authorize your app via the browser:

use drive_v3::Credentials;

// This is the file downloaded in the Setup section
let client_secrets_path = "my_client_secrets.json";

// The OAuth scopes you need
let scopes: [&'static str; 2] = [
    "https://www.googleapis.com/auth/drive.metadata.readonly",
    "https://www.googleapis.com/auth/drive.file",
];

let credentials = Credentials::from_client_secrets_file(&client_secrets_path, &scopes)?;

Great! now you have valid credentials to make requests to Google's API, however these credentials will expire after some time, at which point you will have to request them again.

To avoid having to authorize using the browser every time they expire, you should save them to your system:

credentials.store("very/secure/path/to/my/credentials.json")?;

Now you don't need to worry about requesting new credentials every time, instead you can simply check if they have expired and refresh them if necessary:

use drive_v3::Credentials;

// Path where the credentials were stored
let credentials_storage_path = "very/secure/path/to/my/credentials.json";

// The OAuth scopes you need
let scopes: [&'static str; 2] = [
    "https://www.googleapis.com/auth/drive.metadata.readonly",
    "https://www.googleapis.com/auth/drive.file",
];

let mut stored_credentials = Credentials::from_file(&credentials_storage_path, &scopes)?;

// Refresh the credentials if they have expired
if !stored_credentials.are_valid() {
    stored_credentials.refresh()?;

    // Save them so we don't have to refresh them every time
    stored_credentials.store(&credentials_storage_path)?;
}

Making requests

Now that we have valid Credentials, we can start making requests. For this we need to create a Drive.

A Drive is the representation of the API itself, with it we can make request to any endpoint in Google's API.

To create it we simply need to pass it the Credentials:

use drive_v3::Drive;

let drive = Drive::new(&credentials);

And then make the requests you want, for example list the files in a Drive:

let file_list = drive.files.list()
    .fields("files(name, id, mimeType)") // Set what fields will be returned
    .q("name = 'file_im_looking_for' and not trashed") // search for specific files
    .execute()?;

if let Some(files) = file_list.files {
    for file in &files {
        println!("{}", file);
    }
}

As you can see the files.list function uses the builder pattern, this allows you to specify the query parameters that you need in your request.

Thanks to this pattern you can search the documentation of a specific resource in Google's reference and use any of its query parameters which will have corresponding functions with the same name (the only difference being that the functions will use snake_case instead of camelCase).

Request responses

As seen in the previous section to get a response from one of the Drive's resources you have to call .execute() this will return a Result which will either be an Error or the response from Google's API.

The type of the response will depend on the request, it could return nothing, an object like a File or a Comment or a vector of bytes. You can check the return types in each request's documentation.

Objects

Some request will either return an object or need one for the request, an object is a representation of the types in Google's API.

All objects in drive-v3 have the same structure, a struct with fields that are all an Option<T>. The reason for this is that not all of the fields of an object will be populated by a request or needed to make one.

For example the File object has 60 different fields, it would be impractical to have to specify all fields when you want to create a new file. So instead you can just populate the fields that you actually want to set and leave the rest as None. This is easy since all objects implement the default trait:

use drive_v3::objects::File;

let file = File {
    name: Some( "my-file.txt".to_string() ),
    mime_type: Some( "text/plain".to_string() ),
    description: Some( "this is a text file".to_string() )
    ..Default::default()
};

And when it comes to responses, all requests have the function fields() which you can set to return the exact fields you need, improving performance in your method call. Check Google's documentation for more info on the fields parameter.

More examples

Upload a new file to a Drive:

use drive_v3::objects::{File, UploadType};

// Set what information the uploaded file wil have
let metadata = File {
    name: Some( "my-new-file.txt".to_string() ),
    mime_type: Some( "text/plain".to_string() ),
    ..Default::default()
};

// You can set a callback that will be called when a resumable upload progresses
fn progress_callback( total_bytes: usize, uploaded_bytes: usize ) {
    println!("Uploaded {} bytes, out of a total of {}.", uploaded_bytes, total_bytes);
}

let my_new_file = drive.files.create()
    .upload_type(UploadType::Resumable)
    .callback(progress_callback)
    .metadata(&metadata)
    .content_source("path/to/file.txt")
    .execute()?;

assert_eq!(my_new_file.name, metadata.name);
assert_eq!(my_new_file.mime_type, metadata.mime_type);

Download a file from Drive:

let file_id = "some-file-id";

let file_bytes = drive.files.get_media(&file_id)
    // .save_to("my_downloaded_file.txt") // Save the contents to a path
    .execute()?;

let content = String::from_utf8_lossy(&file_bytes);
println!("file content: {}", content);

Get information about a Drive:

let information = drive.about.get()
    .fields("storageQuota, canCreateDrives, appInstalled")
    .execute()?;

println!("look at all this information:\n{}", information);

Contributing

Pull requests are welcome. For major changes, please open an issue first.

License

MIT

Dependencies

~3.5–5MB
~93K SLoC