Skip to content

Commit 40e8e6b

Browse files
committed
feat: add an option for custom api url
1 parent c1bb1ff commit 40e8e6b

4 files changed

Lines changed: 31 additions & 18 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ repository = "https://github.com/NTUST-Hack/q"
77

88

99
[dependencies]
10-
reqwest = { version = "0.11", features = ["json", "blocking"] }
10+
reqwest = { version = "0.12.5", features = ["json"] }
1111
serde = "1.0.196"
1212
serde-aux = "4.4.0"
1313
serde_derive = "1.0.196"
1414
serde_json = "1.0.1"
1515
serde_with = "3.8.1"
1616
tokio = { version = "1", features = ["full"] }
17+
url = "2.5.2"
1718

1819
[dev-dependencies]
1920
anyhow = "1.0.86"

src/async_impl/mod.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
use std::collections::HashMap;
22

3+
use url::Url;
4+
35
use crate::{
46
default_reqwest_builder, CourseDetails, CourseInfo, Language, QueryError, SearchOptions,
7+
DEFAULT_API_URL,
58
};
69

7-
#[derive(Default, Debug)]
10+
#[derive(Debug)]
811
pub struct ClientBuilder {
912
reqwest_client: reqwest::Client,
13+
base_url: Url,
1014
}
1115

1216
impl ClientBuilder {
1317
pub fn new() -> Self {
1418
ClientBuilder {
1519
reqwest_client: default_reqwest_builder().build().unwrap(),
20+
base_url: Url::parse(&DEFAULT_API_URL).unwrap(),
1621
}
1722
}
1823

@@ -21,15 +26,22 @@ impl ClientBuilder {
2126
self
2227
}
2328

29+
pub fn api_url(mut self, url: Url) -> Self {
30+
self.base_url = url;
31+
self
32+
}
33+
2434
pub fn build(self) -> Q {
2535
Q {
2636
http_client: self.reqwest_client,
37+
base_url: self.base_url,
2738
}
2839
}
2940
}
3041

3142
pub struct Q {
3243
http_client: reqwest::Client,
44+
base_url: Url,
3345
}
3446

3547
impl Q {
@@ -42,13 +54,9 @@ impl Q {
4254
options: &SearchOptions,
4355
merge_courses: bool,
4456
) -> Result<Vec<CourseInfo>, QueryError> {
45-
let resp = match self
46-
.http_client
47-
.post("https://querycourse.ntust.edu.tw/querycourse/api/courses")
48-
.json(&options)
49-
.send()
50-
.await
51-
{
57+
let url = self.base_url.join("courses").unwrap();
58+
59+
let resp = match self.http_client.post(url).json(&options).send().await {
5260
Ok(resp) => resp,
5361
Err(e) => return Err(QueryError::HttpError(format!("{}", e))),
5462
};
@@ -69,18 +77,16 @@ impl Q {
6977
course_no: &str,
7078
language: Language,
7179
) -> Result<CourseDetails, QueryError> {
80+
// is "coursedetials" not "coursedetails"
81+
// looks like an idiotic typo in the API
82+
let url = self.base_url.join("coursedetials").unwrap();
83+
7284
let mut params = HashMap::new();
7385
params.insert("semester", semester);
7486
params.insert("course_no", course_no);
7587
params.insert("language", language.as_str());
7688

77-
let resp = match self
78-
.http_client
79-
.get("https://querycourse.ntust.edu.tw/querycourse/api/coursedetials")
80-
.query(&params)
81-
.send()
82-
.await
83-
{
89+
let resp = match self.http_client.get(url).query(&params).send().await {
8490
Ok(resp) => resp,
8591
Err(e) => return Err(QueryError::HttpError(format!("{}", e))),
8692
};
@@ -91,12 +97,10 @@ impl Q {
9197
};
9298

9399
// # debug
94-
95100
// let text = match String::from_utf8(full.to_vec()) {
96101
// Ok(bytes) => bytes,
97102
// Err(e) => return Err(QueryError::ParseError(format!("{}", e))),
98103
// };
99-
100104
// println!("{}", text);
101105

102106
let json = match serde_json::from_slice::<Vec<CourseDetails>>(&full) {

src/blocking/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ impl ClientBuilder {
2020
self
2121
}
2222

23+
pub fn api_url(mut self, url: url::Url) -> Self {
24+
self.async_builder = self.async_builder.api_url(url);
25+
self
26+
}
27+
2328
pub fn build(self) -> Q {
2429
Q {
2530
async_q: self.async_builder.build(),

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::{collections::HashMap, fmt, str::FromStr, time::Duration};
88

99
pub const DEFAULT_USER_AGENT: &'static str = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36";
1010
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
11+
pub const DEFAULT_API_URL: &'static str = "https://querycourse.ntust.edu.tw/querycourse/api/";
1112

1213
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
1314
#[serde(rename_all = "lowercase")]
@@ -236,6 +237,7 @@ pub fn default_reqwest_builder() -> reqwest::ClientBuilder {
236237

237238
#[derive(Debug, Clone)]
238239
pub enum QueryError {
240+
InputError(String),
239241
HttpError(String),
240242
ParseError(String),
241243
}
@@ -245,6 +247,7 @@ impl std::error::Error for QueryError {}
245247
impl fmt::Display for QueryError {
246248
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
247249
match self {
250+
QueryError::InputError(msg) => write!(f, "Input Error: {}", msg),
248251
QueryError::HttpError(msg) => write!(f, "HTTP Error: {}", msg),
249252
QueryError::ParseError(msg) => write!(f, "Parse Error: {}", msg),
250253
}

0 commit comments

Comments
 (0)