Skip to main content

open_library_api_rs/
lib.rs

1// v0.0.1
2#![forbid(unsafe_code)]
3
4//! # open-library-api-rs
5//!
6//! Async Rust client for the [Open Library API](https://openlibrary.org/developers/api).
7//!
8//! Covers every documented public read endpoint: works, editions, books (bibkey),
9//! authors, full-text search (5 variants), subjects, covers, user lists, reading
10//! logs, the partner/volumes API, recent changes, and generic query/history.
11//!
12//! ## Features
13//!
14//! - **Complete coverage** — all 12 Open Library API domains, 30+ methods
15//! - **Strongly typed** — dedicated response structs; `#[serde(default)]` so new
16//!   API fields never break deserialization
17//! - **Built-in rate limiting** — token-bucket via [`governor`]; 1 req/s default,
18//!   3 req/s with an identifying `User-Agent`
19//! - **Input validation** — OLIDs, ISBN-10/13, slugs, usernames, bibkeys, dates
20//!   all validated before any HTTP call
21//! - **Secure** — `rustls` TLS, 10 MB body cap, `#![forbid(unsafe_code)]`
22//! - **Blocking API** — sync wrappers behind the `blocking` feature flag
23//!
24//! ## Quick start
25//!
26//! ```no_run
27//! use open_library_api_rs::{OpenLibraryClient, Result};
28//! use open_library_api_rs::models::search::SearchParams;
29//!
30//! #[tokio::main]
31//! async fn main() -> Result<()> {
32//!     // 1 req/s, rustls TLS, 10 s connect / 30 s request timeout
33//!     let client = OpenLibraryClient::builder().build()?;
34//!
35//!     // Fetch a work by its Open Library Work ID
36//!     let work = client.get_work("OL45804W").await?;
37//!     println!("Title: {:?}", work.title);
38//!     println!("Subjects: {:?}", work.subjects);
39//!
40//!     // Search across all works
41//!     let results = client.search(SearchParams {
42//!         q: Some("rust programming".into()),
43//!         limit: Some(5),
44//!         ..Default::default()
45//!     }).await?;
46//!     println!("Found {} results", results.num_found);
47//!     for doc in &results.docs {
48//!         println!("  {:?}", doc.title);
49//!     }
50//!
51//!     Ok(())
52//! }
53//! ```
54//!
55//! ## Client configuration
56//!
57//! ```no_run
58//! use open_library_api_rs::{OpenLibraryClient, Result};
59//!
60//! # async fn example() -> Result<()> {
61//! let client = OpenLibraryClient::builder()
62//!     // Supply a contact email to unlock the 3 req/s identified tier
63//!     .contact_email("me@example.com")?
64//!     .rate_limit(3)
65//!     .build()?;
66//! # Ok(())
67//! # }
68//! ```
69//!
70//! [`OpenLibraryClient`] is `Clone + Send + Sync` — clone it cheaply to share
71//! across tasks or threads.
72//!
73//! See [`client::OpenLibraryClientBuilder`] for the full set of builder options.
74//!
75//! ## Cargo features
76//!
77//! | Feature | Default | Description |
78//! |---|---|---|
79//! | `rustls-tls` | **on** | TLS via `rustls` (no system certs needed) |
80//! | `native-tls` | off | TLS via the OS / OpenSSL |
81//! | `blocking` | off | Sync wrappers for every async method |
82//!
83//! [`governor`]: https://docs.rs/governor
84
85pub mod api;
86pub mod client;
87pub mod error;
88pub mod models;
89pub mod validation;
90
91#[cfg(feature = "blocking")]
92pub mod blocking;
93
94// Top-level re-exports for ergonomic imports.
95pub use client::OpenLibraryClient;
96pub use error::{Error, Result};