166 stable releases (22 major)

new 64.2.5 Apr 16, 2024
64.2.0 Mar 26, 2024
62.0.0 Mar 14, 2024
61.0.0 Mar 13, 2024
40.0.3 Jan 25, 2021

#196 in Web programming

Download history 2/week @ 2023-12-22 34/week @ 2024-01-05 43/week @ 2024-01-12 89/week @ 2024-01-19 27/week @ 2024-01-26 16/week @ 2024-02-02 2/week @ 2024-02-09 197/week @ 2024-02-16 211/week @ 2024-02-23 206/week @ 2024-03-01 169/week @ 2024-03-08 239/week @ 2024-03-15 396/week @ 2024-03-22 440/week @ 2024-03-29 1303/week @ 2024-04-05

2,480 downloads per month
Used in 2 crates

MPL-2.0 license

330KB
4.5K SLoC

Taskcluster API Client

This library is a complete interface to Taskcluster in Rust. It provides asynchronous interfaces for all Taskcluster API methods, as well as a few utility functions.

Usage

See docs.rs for detailed usage information.

Compatibility

This library is co-versioned with Taskcluster itself. That is, a client with version x.y.z contains API methods corresponding to Taskcluster version x.y.z. Taskcluster is careful to maintain API compatibility, and guarantees it within a major version. That means that any client with version x.* will work against any Taskcluster services at version x.*, and is very likely to work for many other major versions of the Taskcluster services. Any incompatibilities are noted in the Changelog.


lib.rs:

Taskcluster Client for Rust

For a general guide to using Taskcluster clients, see Calling Taskcluster APIs.

This client is a convenience wrapper around reqwest that provides named functions for each API endpoint and adds functionality such as authentication and retries.

Usage

Setup

Before calling an API end-point, you'll need to build a client, using the ClientBuilder type. This allows construction of a client with only the necessary features, following the builder pattern. You must at least supply a root URL to identify the Taskcluster deployment to which the API calls should be directed.

There is a type for each service, e.g., Queue and Auth. Each service type defines functions spepcific to the API endpoints for that service. Each has a new associated function that takes an Into<ClientBuilder>. As a shortcut, you may pass a string to new that will be treated as a root URL.

Here is a simple setup and use of an un-authenticated client:

use taskcluster::Auth;
let auth = Auth::new(root_url)?;
let resp = auth.client("static/taskcluster/root").await?;
assert_eq!(resp, json!({"clientId": "static/taskcluster/root"}));
Ok(())

Here is an example with credentials provided, in this case via the standard environment variables.

use std::env;
use taskcluster::{ClientBuilder, Queue, Credentials};
let creds = Credentials::from_env()?;
let root_url = env::var("TASKCLUSTER_ROOT_URL").unwrap();
let client = Queue::new(ClientBuilder::new(&root_url).credentials(creds))?;
let res = client.cancelTask("G08bnnBuR6yDhDLJkJ6KiA").await?;
println!("{}", res.get("status").unwrap());
Ok(())

Authorized Scopes

If you wish to perform requests on behalf of a third-party that has smaller set of scopes than you do, you can specify which scopes your request should be allowed to use.

These "authorized scopes" are configured on the client:

use std::env;
use serde_json::json;
use taskcluster::{ClientBuilder, Queue, Credentials};
let creds = Credentials::from_env()?;
let root_url = env::var("TASKCLUSTER_ROOT_URL").unwrap();
let client = Queue::new(
ClientBuilder::new(&root_url)
.credentials(creds)
.authorized_scopes(vec!["just:one-scope"]))?;
let res = client.createTask("G08bnnBuR6yDhDLJkJ6KiA", &task).await?;
Ok(())

Calling API Methods

API methods are available as methods on the corresponding client object. They are capitalized in snakeCase (e.g., createTask) to match the Taskcluster documentation.

Each method takes arguments in the following order, where appropriate to the method:

  • Positional arguments (strings interpolated into the URL)
  • Request body (payload)
  • URL query arguments

The payload comes in the form of a serde_json::Value, the contents of which should match the API method's input schema. URL query arguments are all optional.

For example, the following lists all Auth clients:

use taskcluster::{Auth, ClientBuilder, Credentials};
let auth = Auth::new(ClientBuilder::new(&root_url))?;
let mut continuation_token: Option<String> = None;
let limit = Some("10");

loop {
let res = auth
.listClients(None, continuation_token.as_deref(), limit)
.await?;
for client in res.get("clients").unwrap().as_array().unwrap() {
println!("{:?}", client);
}
if let Some(v) = res.get("continuationToken") {
continuation_token = Some(v.as_str().unwrap().to_owned());
} else {
break;
}
}

Error Handling

All 5xx (server error) responses are automatically retried. All 4xx (client error) responses are converted to Result::Err. All other responses are treated as successful responses. Note that this includes 3xx (redirection) responses; the client does not automatically follow such redirects.

Client methods return anyhow::Error, but this can be downcast to a reqwest::Error if needed. As a shortcut for the common case of getting the HTTP status code for an error, use err_status_code. The reqwest::StatusCode type that this returns is re-exported from this crate.

Low-Level Access

Instead of using service-specific types, it is possible to call API methods directly by path, using the Client type:

use std::env;
use taskcluster::{ClientBuilder, Credentials};
let creds = Credentials::from_env()?;
let root_url = env::var("TASKCLUSTER_ROOT_URL").unwrap();
let client = ClientBuilder::new(&root_url).credentials(creds).build()?;
let resp = client.request("POST", "api/queue/v1/task/G08bnnBuR6yDhDLJkJ6KiA/cancel", None, None).await?;
assert!(resp.status().is_success());

Uploading and Downloading Objects

The taskcluster-upload and taskcluster-download crates contain dedicated support for resilient uploads and downloads to/from the Taskcluster object service. This comes in the form of functions that will both interface with the object service API and perform the negotiated upload/download method. In all cases, you must supply a pre-configured Object client, as well as required parameters to the object service API methods.

Generating URLs

To generate a unsigned URL for an API method, use <method>_url:

use taskcluster::{Auth, ClientBuilder};
let root_url = env::var("TASKCLUSTER_ROOT_URL").unwrap();
let auth = Auth::new(ClientBuilder::new(&root_url))?;
let url = auth.listClients_url(Some("static/"), None, None)?;
assert_eq!(url, "https://tc-tests.example.com/api/auth/v1/clients/?prefix=static%2F".to_owned());

Generating Temporary Credentials

The create_named_temp_creds method creates temporary credentials:

use std::env;
use std::time::Duration;
use taskcluster::Credentials;
let creds = Credentials::from_env()?;
let temp_creds = creds.create_named_temp_creds(
"new-client-id",
Duration::from_secs(3600),
vec!["scope1", "scope2"])?;
assert_eq!(temp_creds.client_id, "new-client-id");

There is also a create_temp_creds method which creates unamed temporary credentials, but its use is not recommended.

Generating Timestamps

Taskcluster APIs expects ISO 8601 timestamps, of the sort generated by the JS Date.toJSON method. The chrono crate supports generating compatible timestamps if included with the serde feature. This crate re-exports chrono with that feature enabled. To duplicate the functionality of the fromNow function from other Taskcluster client libraries, use something like this:

use taskcluster::chrono::{DateTime, Utc, Duration};
use serde_json::json;

let expires = Utc::now() + Duration::days(2);
let json = json!({ "expires": expires });

Generating SlugIDs

Use the slugid crate to create slugIds (such as for a taskId).

Dependencies

~13–27MB
~499K SLoC