osu_api/api_v1/
req.rs

1use std::collections::HashMap;
2
3use crate::api_v1::{
4  ApiEndpoint, Error, GetBeatmapsProps, GetBeatmapsResp, GetUserRecentProp, GetUserRecentResp,
5  OsuApiRequester,
6};
7
8type QueryParam = HashMap<&'static str, String>;
9
10#[async_trait::async_trait]
11impl OsuApiRequester for reqwest::Client {
12  async fn get_user_recent<'k, 'u>(
13    &self,
14    param: GetUserRecentProp<'k, 'u>,
15  ) -> Result<Vec<GetUserRecentResp>, Error> {
16    let param: QueryParam = param.into();
17    let url = reqwest::Url::parse_with_params(ApiEndpoint::GET_USER_RECENT, &param)
18      .expect("fail to turn GetUserRecentProp into params");
19    let resp = self.get(url).send().await?.bytes().await?;
20    let recent: Vec<GetUserRecentResp> = serde_json::from_slice(&resp)?;
21
22    Ok(recent)
23  }
24
25  async fn get_beatmaps<'u, 'k>(
26    &self,
27    param: GetBeatmapsProps<'u, 'k>,
28  ) -> Result<Vec<GetBeatmapsResp>, Error> {
29    let param: HashMap<&'static str, String> =
30      param.try_into().map_err(|_| Error::InvalidRequestParams)?;
31    let url = reqwest::Url::parse_with_params(ApiEndpoint::GET_BEATMAPS, &param)
32      .expect("fail to turn given param into query");
33    let resp = self.get(url).send().await?.bytes().await?;
34    let recent: Vec<GetBeatmapsResp> = serde_json::from_slice(&resp)?;
35    Ok(recent)
36  }
37}
38
39#[tokio::test]
40async fn test_get_user_recent() {
41  dotenvy::dotenv().ok();
42
43  let api_key = std::env::var("OSU_API_KEY").expect("Require env `OSU_API_KEY` set");
44
45  let props = GetUserRecentProp::builder()
46    .api_key(&api_key)
47    .user_info("BlackDog5")
48    .limit(1)
49    .build();
50  let client = reqwest::Client::new();
51  let resp = client.get_user_recent(props).await.unwrap();
52
53  assert!(!resp.is_empty())
54}
55
56#[tokio::test]
57async fn test_get_beatmaps() {
58  dotenvy::dotenv().ok();
59
60  let api_key = std::env::var("OSU_API_KEY").expect("Require env `OSU_API_KEY` set");
61  let client = reqwest::Client::new();
62
63  // #1 Test get beatmap set
64  let props = GetBeatmapsProps::builder()
65    .api_key(&api_key)
66    .beatmapset_id(896080)
67    .build();
68  let resp = client.get_beatmaps(props).await.unwrap();
69  // tsukinami have 3 difficulties
70  assert_eq!(resp.len(), 3);
71
72  // #2 Test get single difficulty
73  let props = GetBeatmapsProps::builder()
74    .api_key(&api_key)
75    .beatmap_id(1872396)
76    .build();
77  let resp = client.get_beatmaps(props).await.unwrap();
78  assert_eq!(resp.len(), 1);
79
80  use super::ModsFlag;
81
82  // #3 Test mods
83  let props = GetBeatmapsProps::builder()
84    .api_key(&api_key)
85    .beatmap_id(1872396)
86    .mods(vec![ModsFlag::DOUBLETIME, ModsFlag::EASY])
87    .build();
88  let resp = client.get_beatmaps(props).await.unwrap();
89  assert!(!resp.is_empty());
90
91  // ensure mods is applied
92  let map = &resp[0];
93  assert!(map.difficultyrating > 6.01);
94}