use std::error::Error;
use reqwest::Url;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use author_search::{AuthorSearchParams, AuthorSearchResult};
use floor_list::FloorListParams;
use floor_list::FloorListResult;
use crate::ApiParams::{AuthorSearch, FloorList};
mod author_search;
mod floor_list;
const ENDPOINT_BASE: &str = "https://api.dmm.com/affiliate/v3/";
#[derive(Serialize, Debug)]
#[serde(untagged)]
enum ApiParams {
FloorList(FloorListParams),
AuthorSearch(AuthorSearchParams),
}
#[derive(Deserialize, Debug)]
pub struct ApiResponse<T: ApiResult> {
pub result: T,
}
pub trait ApiResult {}
pub struct Dmm {
api_id: String,
affiliate_id: String,
}
impl Dmm {
pub fn new(dmm_api_id: &str, dmm_affiliate_id: &str) -> Self {
Dmm {
api_id: dmm_api_id.to_string(),
affiliate_id: dmm_affiliate_id.to_string(),
}
}
async fn call<T>(&self, api: &str, params: ApiParams) -> Result<ApiResponse<T>, Box<dyn Error>>
where
T: ApiResult + DeserializeOwned,
{
let auth = querystring::stringify(vec![
("api_id", &self.api_id),
("affiliate_id", &self.affiliate_id),
]);
let qs = serde_qs::to_string(¶ms)?;
let mut url = Url::parse(ENDPOINT_BASE)?.join(api)?;
url.set_query(Some(&(auth + &qs)));
let res = reqwest::get(url).await?;
let text = res.text().await?;
let res = serde_json::from_str(&text)?;
Ok(res)
}
pub async fn floor_list(
&self,
params: FloorListParams,
) -> Result<ApiResponse<FloorListResult>, Box<dyn Error>> {
self.call("FloorList", FloorList(params)).await
}
pub async fn author_search(
&self,
params: AuthorSearchParams,
) -> Result<ApiResponse<AuthorSearchResult>, Box<dyn Error>> {
self.call("AuthorSearch", AuthorSearch(params)).await
}
}
#[cfg(test)]
mod tests {
use std::env;
use super::*;
#[tokio::test]
async fn test_floor_list() {
let api_id = env::var("DMM_API_ID").unwrap();
let affiliate_id = env::var("DMM_AFFILIATE_ID").unwrap();
let dmm = Dmm::new(&api_id, &affiliate_id);
let r = dmm.floor_list(FloorListParams {}).await.unwrap();
assert_eq!(r.result.site.get(0).unwrap().name, "DMM.com(一般)");
}
#[tokio::test]
async fn test_author_search() {
let api_id = env::var("DMM_API_ID").unwrap();
let affiliate_id = env::var("DMM_AFFILIATE_ID").unwrap();
let dmm = Dmm::new(&api_id, &affiliate_id);
let r = dmm
.author_search(AuthorSearchParams {
floor_id: "27".to_string(),
initial: Some('と'),
offset: Some(100),
..AuthorSearchParams::default()
})
.await
.unwrap();
assert_eq!(r.result.status, "200");
}
}