use cameo::{CameoClient, MediaId, ProviderError, TmdbConfig, unified::CameoClientError};
#[tokio::main]
async fn main() {
let _ = dotenvy::dotenv();
demo_build_time_errors();
demo_api_errors().await;
demo_not_found().await;
demo_propagation_styles().await;
}
fn demo_build_time_errors() {
println!("=== Build-time errors ===");
match CameoClient::builder().build() {
Ok(_) => println!(" [unexpected] client built with no providers"),
Err(CameoClientError::NotConfigured) => {
println!(" [ok] NotConfigured: must configure at least one provider");
}
Err(e) => println!(" [unexpected] {e}"),
}
match CameoClient::builder()
.with_tmdb(TmdbConfig::new(""))
.build()
{
Ok(_) => println!(" [unexpected] empty token accepted"),
Err(CameoClientError::Provider(ProviderError::InvalidInput(msg))) => {
println!(" [ok] InvalidInput: {msg}");
}
Err(e) => println!(" [unexpected] {e}"),
}
println!();
}
async fn demo_api_errors() {
println!("=== API errors (invalid token → auth failure) ===");
let client = match CameoClient::builder()
.with_tmdb(TmdbConfig::new("invalid-token"))
.build()
{
Ok(c) => c,
Err(e) => {
println!(" build failed unexpectedly: {e}");
println!();
return;
}
};
match client.search_movies("Inception", None).await {
Ok(results) => println!(" [unexpected] got {} results", results.total_results),
Err(CameoClientError::Provider(ProviderError::Auth(msg))) => {
println!(" [ok] authentication failed — check your token: {msg}");
}
Err(CameoClientError::Provider(ProviderError::RateLimited { retry_after })) => {
println!(" [ok] rate limited — retry after {retry_after:?}");
}
Err(CameoClientError::Provider(ProviderError::Transport(msg))) => {
println!(" transport error (no network?): {msg}");
}
Err(CameoClientError::Provider(ProviderError::Api { status, message })) => {
println!(" [ok] HTTP {status}: {message}");
}
Err(e) => println!(" unexpected error variant: {e}"),
}
println!();
}
async fn demo_not_found() {
println!("=== Not-found recovery ===");
let Ok(token) = std::env::var("TMDB_API_TOKEN") else {
println!(" skipped — TMDB_API_TOKEN not set\n");
return;
};
let client = match CameoClient::builder()
.with_tmdb(TmdbConfig::new(token))
.build()
{
Ok(c) => c,
Err(e) => {
println!(" build error: {e}\n");
return;
}
};
match client.movie_details(&MediaId::tmdb(999_999_999)).await {
Ok(details) => println!(" [unexpected] found: {}", details.movie.title),
Err(CameoClientError::Provider(ProviderError::NotFound)) => {
println!(" [ok] movie not found — returning default placeholder");
}
Err(e) => println!(" unexpected error: {e}"),
}
println!();
}
async fn demo_propagation_styles() {
println!("=== Propagation styles ===");
match search_with_question_mark("Inception").await {
Ok(count) => println!(" [?-style] found {count} results for 'Inception'"),
Err(e) => println!(" [?-style] skipped or error: {e}"),
}
search_with_match("Inception").await;
println!();
}
async fn search_with_question_mark(query: &str) -> Result<u32, Box<dyn std::error::Error>> {
let token = std::env::var("TMDB_API_TOKEN")?;
let client = CameoClient::builder()
.with_tmdb(TmdbConfig::new(token))
.build()?;
let results = client.search_movies(query, None).await?;
Ok(results.total_results)
}
async fn search_with_match(query: &str) {
let Ok(token) = std::env::var("TMDB_API_TOKEN") else {
println!(" [match-style] skipped — TMDB_API_TOKEN not set");
return;
};
let client = match CameoClient::builder()
.with_tmdb(TmdbConfig::new(token))
.build()
{
Ok(c) => c,
Err(e) => {
println!(" [match-style] build error: {e}");
return;
}
};
match client.search_movies(query, None).await {
Ok(results) => println!(
" [match-style] found {} results for '{query}'",
results.total_results
),
Err(CameoClientError::Provider(ProviderError::Auth(_))) => {
println!(" [match-style] auth failed — check TMDB_API_TOKEN");
}
Err(e) => println!(" [match-style] search failed: {e}"),
}
}