openalex/api_entities/
mod.rs1pub mod author;
2pub mod common_types;
3pub mod concept;
4pub mod funder;
5pub mod institution;
6pub mod keyword;
7pub mod publisher;
8pub mod source;
9pub mod topic;
10pub mod work;
11
12use reqwest::blocking::{Client, Response};
13
14use crate::{
15 prelude::*,
16 utils::{filter::Filter, sort::Sort},
17};
18
19#[macro_export]
20macro_rules! impl_try_from_for_single_entity {
21 ($entity:ty) => {
22 impl TryFrom<reqwest::blocking::Response> for $entity {
23 type Error = $crate::error::Error;
24
25 fn try_from(response: reqwest::blocking::Response) -> $crate::prelude::Result<Self> {
26 match response.status() {
27 reqwest::StatusCode::OK => {
28 let res = response.json::<Self>();
29 match res {
30 Ok(entity) => Ok(entity),
31 Err(e) => Err($crate::error::Error::Generic(format!(
32 "Error deserializing object. Original Message: {}",
33 e
34 ))),
35 }
36 }
37 reqwest::StatusCode::NOT_FOUND => {
38 let oa_error = $crate::error::OpenAlexError {
39 error: "Document not found".to_string(),
40 message: "The document with the specified id was not found. HTTP 404"
41 .to_string(),
42 };
43 Err($crate::error::Error::OpenAlex(oa_error))
44 }
45 _ => Err($crate::error::Error::Generic(format!(
46 "Unknown Error. Response Code was {}",
47 response.status()
48 ))),
49 }
50 }
51 }
52 };
53}
54
55#[macro_export]
56macro_rules! impl_try_from_for_entity_response {
57 ($entity_response:ty) => {
58 impl TryFrom<reqwest::blocking::Response> for $entity_response {
59 type Error = $crate::error::Error;
60
61 fn try_from(response: reqwest::blocking::Response) -> $crate::prelude::Result<Self> {
62 match response.status() {
63 reqwest::StatusCode::OK => {
64 let res = response.json::<Self>();
65 match res {
66 Ok(author_response) => Ok(author_response),
67 Err(e) => Err($crate::error::Error::Generic(format!(
68 "Error deserializing Work object. Original Message: {}",
69 e
70 ))),
71 }
72 }
73 reqwest::StatusCode::FORBIDDEN => {
74 let res = response.json::<$crate::error::OpenAlexError>();
75 match res {
76 Ok(oa_error) => Err($crate::error::Error::OpenAlex(oa_error)),
77 Err(e) => Err($crate::error::Error::Generic(format!(
78 "Error deserializing OpenAlexError object. Original Message: {}",
79 e
80 ))),
81 }
82 }
83 _ => Err($crate::error::Error::Generic(format!(
84 "Unknown Error. Response Code was {}",
85 response.status()
86 ))),
87 }
88 }
89 }
90 };
91}
92
93pub trait APIEntity<EntityType, ResponseType>
94where
95 EntityType: TryFrom<Response, Error = Error>,
96 ResponseType: TryFrom<Response, Error = Error>,
97{
98 const API_URL: &'static str;
99
100 #[allow(clippy::new_ret_no_self)]
101 fn new(id: &str) -> Result<EntityType> {
102 let url = format!("{}/{}", Self::API_URL, id);
103 let response = reqwest::blocking::get(url)?;
104 response.try_into()
105 }
106 fn get_samples(number_of_samples: u32, seed: impl Into<String>) -> Result<ResponseType> {
107 let client = Client::new();
108 let response = client
109 .get(Self::API_URL)
110 .query(&[
111 ("sample", number_of_samples.to_string()),
112 ("seed", seed.into()),
113 ])
114 .send()?;
115 response.try_into()
116 }
117 fn filter(filter: Filter, page: u32, per_page: u32, sort: Sort) -> Result<ResponseType> {
118 let client = Client::new();
119 let response = client
120 .get(Self::API_URL)
121 .query(&[
122 ("filter", filter.to_string()),
123 ("page", page.to_string()),
124 ("per-page", per_page.to_string()),
125 ("sort", sort.to_string()),
126 ])
127 .send()?;
128 response.try_into()
129 }
130
131 fn search(
132 search: impl Into<String>,
133 page: u32,
134 per_page: u32,
135 sort: Sort,
136 ) -> Result<ResponseType> {
137 let client = Client::new();
138 let response = client
139 .get(Self::API_URL)
140 .query(&[
141 ("search", search.into()),
142 ("page", page.to_string()),
143 ("per-page", per_page.to_string()),
144 ("sort", sort.to_string()),
145 ])
146 .send()?;
147
148 response.try_into()
149 }
150}