open-library-api-rs 0.1.0

Async Rust client for the Open Library API
Documentation
// v0.0.1
#![forbid(unsafe_code)]

//! # open-library-api-rs
//!
//! Async Rust client for the [Open Library API](https://openlibrary.org/developers/api).
//!
//! Covers every documented public read endpoint: works, editions, books (bibkey),
//! authors, full-text search (5 variants), subjects, covers, user lists, reading
//! logs, the partner/volumes API, recent changes, and generic query/history.
//!
//! ## Features
//!
//! - **Complete coverage** — all 12 Open Library API domains, 30+ methods
//! - **Strongly typed** — dedicated response structs; `#[serde(default)]` so new
//!   API fields never break deserialization
//! - **Built-in rate limiting** — token-bucket via [`governor`]; 1 req/s default,
//!   3 req/s with an identifying `User-Agent`
//! - **Input validation** — OLIDs, ISBN-10/13, slugs, usernames, bibkeys, dates
//!   all validated before any HTTP call
//! - **Secure** — `rustls` TLS, 10 MB body cap, `#![forbid(unsafe_code)]`
//! - **Blocking API** — sync wrappers behind the `blocking` feature flag
//!
//! ## Quick start
//!
//! ```no_run
//! use open_library_api_rs::{OpenLibraryClient, Result};
//! use open_library_api_rs::models::search::SearchParams;
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//!     // 1 req/s, rustls TLS, 10 s connect / 30 s request timeout
//!     let client = OpenLibraryClient::builder().build()?;
//!
//!     // Fetch a work by its Open Library Work ID
//!     let work = client.get_work("OL45804W").await?;
//!     println!("Title: {:?}", work.title);
//!     println!("Subjects: {:?}", work.subjects);
//!
//!     // Search across all works
//!     let results = client.search(SearchParams {
//!         q: Some("rust programming".into()),
//!         limit: Some(5),
//!         ..Default::default()
//!     }).await?;
//!     println!("Found {} results", results.num_found);
//!     for doc in &results.docs {
//!         println!("  {:?}", doc.title);
//!     }
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Client configuration
//!
//! ```no_run
//! use open_library_api_rs::{OpenLibraryClient, Result};
//!
//! # async fn example() -> Result<()> {
//! let client = OpenLibraryClient::builder()
//!     // Supply a contact email to unlock the 3 req/s identified tier
//!     .contact_email("me@example.com")?
//!     .rate_limit(3)
//!     .build()?;
//! # Ok(())
//! # }
//! ```
//!
//! [`OpenLibraryClient`] is `Clone + Send + Sync` — clone it cheaply to share
//! across tasks or threads.
//!
//! See [`client::OpenLibraryClientBuilder`] for the full set of builder options.
//!
//! ## Cargo features
//!
//! | Feature | Default | Description |
//! |---|---|---|
//! | `rustls-tls` | **on** | TLS via `rustls` (no system certs needed) |
//! | `native-tls` | off | TLS via the OS / OpenSSL |
//! | `blocking` | off | Sync wrappers for every async method |
//!
//! [`governor`]: https://docs.rs/governor

pub mod api;
pub mod client;
pub mod error;
pub mod models;
pub mod validation;

#[cfg(feature = "blocking")]
pub mod blocking;

// Top-level re-exports for ergonomic imports.
pub use client::OpenLibraryClient;
pub use error::{Error, Result};