Open10

RustでTogglAPIを叩く

koheikohei

Cargo.tomlにdependenciesを追加

serde_json = "1.0.64"
tokio = { version = "1.16.1", features = ["full"] }
reqwest = { version = "0.11.20", features = ["json"] }
koheikohei

まずは、APIが叩けるようにする

main.rsを以下のように修正

extern crate serde_json;
extern crate tokio;
use reqwest::header::CONTENT_TYPE;
use reqwest::Client;
use reqwest::Method;

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let client = Client::new();
    let api_token = match std::env::var("API_TOKEN") {
        Ok(val) => val,
        Err(_e) => "dev".to_string(),
    };

    let json = client
        .request(
            Method::GET,
            "https://api.track.toggl.com/api/v9/me/time_entries".to_string(),
        )
        // NOTE: passwordがOption<P>なので、Some("api_token")を渡す
        .basic_auth(api_token, Some("api_token"))
        .header(CONTENT_TYPE, "application/json")
        .send()
        .await?;

    let body = json.text().await?;

    println!("{:#?}", body);

    Ok(())
}
koheikohei

環境変数にAPIをセットする

export API_TOKEN={TogglのAPI Token}
koheikohei

レスポンスをパースできるようにする

TimeEntryの構造体を用意する

#[derive(Debug, Deserialize)]
struct TimeEntry {
    at: String,
    billable: bool,
    description: String,
    duration: i64,
    duronly: bool,
    id: i64,
    pid: i64,
    project_id: Option<i64>,
    server_deleted_at: Option<String>,
    start: String,
    stop: Option<String>,
    tag_ids: Vec<i64>,
    tags: Vec<String>,
    task_id: Option<i64>,
    uid: i64,
    user_id: i64,
    wid: i64,
    workspace_id: i64,
}

dependenciesにserdeを追加

serde = { version = "^1.0.130", features = ["derive"] }

レスポンスボディを<Vec<TimeEntry>>型にパースする

let body = res.json::<Vec<TimeEntry>>().await?;
koheikohei

クエリパラメータにstart_dateとend_dateを指定する(本日のtime_entriesのみ取得できるようにする)

日付の操作を行うライブラリのchronoを追加する

use chrono::{DateTime, Local, Timelike};

以下の関数を追加

fn get_start_date() -> String {
    let dt = Local::now();
    let startTime = dt
        .with_hour(0)
        .unwrap()
        .with_minute(0)
        .unwrap()
        .with_second(0)
        .unwrap()
        .to_rfc3339()
        .to_string();
    return startTime;
}

fn get_end_date() -> String {
    let dt = Local::now();
    let startTime = dt
        .with_hour(23)
        .unwrap()
        .with_minute(59)
        .unwrap()
        .with_second(59)
        .unwrap()
        .to_rfc3339()
        .to_string();
    return startTime;
}

.queryの呼び出しを追加

.query(&[("start_date", start_time), ("end_date", end_time)])
koheikohei

全体コード

extern crate serde_json;
extern crate tokio;
use chrono::{DateTime, FixedOffset, Local, Timelike};
use reqwest::header::CONTENT_TYPE;
use reqwest::Client;
use reqwest::Method;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct TimeEntry {
    at: String,
    billable: bool,
    description: String,
    duration: i64,
    duronly: bool,
    id: i64,
    pid: i64,
    project_id: Option<i64>,
    server_deleted_at: Option<String>,
    start: String,
    stop: Option<String>,
    tag_ids: Vec<i64>,
    tags: Vec<String>,
    task_id: Option<i64>,
    uid: i64,
    user_id: i64,
    wid: i64,
    workspace_id: i64,
}

fn get_start_date() -> String {
    let dt = Local::now();
    let start_time = dt
        .with_hour(0)
        .unwrap()
        .with_minute(0)
        .unwrap()
        .with_second(0)
        .unwrap()
        .to_rfc3339()
        .to_string();
    return start_time;
}

fn get_end_date() -> String {
    let dt = Local::now();
    let start_time = dt
        .with_hour(23)
        .unwrap()
        .with_minute(59)
        .unwrap()
        .with_second(59)
        .unwrap()
        .to_rfc3339()
        .to_string();
    return start_time;
}

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let client = Client::new();
    let api_token = match std::env::var("API_TOKEN") {
        Ok(val) => val,
        Err(_e) => "dev".to_string(),
    };

    let start_time = get_start_date();
    let end_time = get_end_date();

    let res = client
        .request(
            Method::GET,
            "https://api.track.toggl.com/api/v9/me/time_entries".to_string(),
        )
        .query(&[("start_date", start_time), ("end_date", end_time)])
        // HACK: passwordがOption<P>なので、Some("api_token")を渡す
        .basic_auth(api_token, Some("api_token"))
        .header(CONTENT_TYPE, "application/json")
        .send()
        .await?;

    let body = res.json::<Vec<TimeEntry>>().await?;
    println!("{:?}", body);
}