headhunter_bindings/
client.rs1use super::{Error, Result, request::*, response::*};
2
3use std::fmt::Display;
4
5pub struct Client {
7 access_token: String,
8 reusable_client: reqwest::Client,
9}
10
11impl Client {
12 const USER_AGENT: &'static str = "App/1.0 (hidden@gmail.com)";
13 const BASE_URL: &'static str = "https://api.hh.ru";
14
15 #[allow(clippy::result_large_err)]
17 pub fn new(access_token: String) -> Result<Self> {
18 Ok(Self {
19 access_token,
20 reusable_client: reqwest::ClientBuilder::new()
21 .user_agent(Self::USER_AGENT)
22 .build()?,
23 })
24 }
25
26 #[inline]
27 #[allow(clippy::result_large_err)]
28 fn build_url<Req: Request>() -> Result<String> {
29 let req = Req::method().ok_or_else(|| Error::UrlBuild)?;
30 Ok(format!("{url}/{req}", url = Self::BASE_URL))
31 }
32
33 #[inline]
34 #[allow(clippy::result_large_err)]
35 fn build_url_with_value<Req: Request, T: Display>(value: T) -> Result<String> {
36 let req = Req::build_url(value).ok_or_else(|| Error::UrlBuild)?;
37 Ok(format!("{url}/{req}", url = Self::BASE_URL))
38 }
39
40 async fn request_base<Url: reqwest::IntoUrl, Req: Request>(
41 &self,
42 method: reqwest::Method,
43 url: Url,
44 req: &Req,
45 ) -> Result<reqwest::Response> {
46 let response = self
47 .reusable_client
48 .request(method, url)
49 .json(req)
50 .bearer_auth(&self.access_token)
51 .send()
52 .await?;
53
54 Ok(response)
55 }
56
57 async fn request<Url: reqwest::IntoUrl, Req: Request>(
58 &self,
59 method: reqwest::Method,
60 url: Url,
61 req: &Req,
62 ) -> Result<Req::Response> {
63 let ret = self.request_base(method, url, req).await?;
64
65 if ret.status() == reqwest::StatusCode::NO_CONTENT {
66 return Ok(serde_json::from_str::<'_, Req::Response>("null")?);
67 }
68
69 let response = ret.json::<HeadhunterResponse<Req::Response>>().await?;
70 match response {
71 HeadhunterResponse::Response(response) => Ok(response),
72 HeadhunterResponse::Error(error) => Err(Error::Headhunter(error)),
73 }
74 }
75
76 pub async fn get<Req: Request>(&self, req: &Req) -> Result<Req::Response> {
78 let url = Self::build_url::<Req>()?;
79 self.request(reqwest::Method::GET, url, req).await
80 }
81
82 pub async fn post_with_value<Req: Request, T: Display>(
84 &self,
85 req: &Req,
86 value: T,
87 ) -> Result<Req::Response> {
88 let url = Self::build_url_with_value::<Req, _>(value)?;
89 self.request(reqwest::Method::POST, url, req).await
90 }
91}