open_library/clients/
books.rs

1use crate::clients::handle;
2use crate::models::books::{BibliographyKey, Book};
3use crate::models::identifiers::{
4    Identifier, InternationalStandardBookNumber, OpenLibraryIdentifier,
5};
6use crate::models::OpenLibraryModel;
7use crate::OpenLibraryError;
8use reqwest::Client;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use url::Url;
12
13#[derive(Clone)]
14pub struct BooksClient {
15    client: Client,
16    host: Url,
17}
18
19type BookSearchResponse = HashMap<BibliographyKey, Book>;
20impl OpenLibraryModel for BookSearchResponse {}
21
22impl BooksClient {
23    pub fn new(client: &Client, host: &Url) -> Self {
24        Self {
25            client: client.clone(),
26            host: host.clone(),
27        }
28    }
29
30    pub async fn by_isbn(
31        &self,
32        isbn: InternationalStandardBookNumber,
33    ) -> Result<Book, OpenLibraryError> {
34        let url = self
35            .host
36            .join(format!("/isbn/{}.json", isbn.value()).as_str())?;
37
38        handle(self.client.get(url)).await
39    }
40
41    pub async fn get(&self, identifier: OpenLibraryIdentifier) -> Result<Book, OpenLibraryError> {
42        let url = self
43            .host
44            .join(format!("/books/{}.json", identifier.value()).as_str())?;
45
46        handle(self.client.get(url)).await
47    }
48
49    pub async fn search<'a, T: Into<&'a Vec<BibliographyKey>>>(
50        &self,
51        identifiers: T,
52    ) -> Result<BookSearchResponse, OpenLibraryError> {
53        let ids_filter = identifiers
54            .into()
55            .iter()
56            .map(|id| id.to_string())
57            .collect::<Vec<String>>()
58            .join(",");
59
60        handle(self.client.get(self.host.join("/api/books")?).query(&[
61            (QueryParameters::BibliographyKeys, &ids_filter),
62            (QueryParameters::Format, &String::from("json")),
63            (QueryParameters::JavascriptCommand, &String::from("data")),
64        ]))
65        .await
66    }
67}
68
69#[derive(Deserialize, Serialize)]
70enum QueryParameters {
71    #[serde(rename = "bibkeys")]
72    BibliographyKeys,
73    #[serde(rename = "format")]
74    Format,
75    #[serde(rename = "jscmd")]
76    JavascriptCommand,
77}