Open10
RustでTogglAPIを叩く
Rustの環境構築
ターミナルで以下のコマンドを実行する
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
プログジェクトの作成
cargo new rust-toggl-api
Cargo.tomlにdependenciesを追加
serde_json = "1.0.64"
tokio = { version = "1.16.1", features = ["full"] }
reqwest = { version = "0.11.20", features = ["json"] }
まずは、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(())
}
toggl APIを発行
環境変数にAPIをセットする
export API_TOKEN={TogglのAPI Token}
実行
cargo run
レスポンスをパースできるようにする
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?;
クエリパラメータに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)])
全体コード
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);
}