itchio-api 0.3.0

Easily interact with the itch.io server-side API
Documentation
use chrono::{DateTime, Utc};
use serde::Deserialize;
use url::Url;

use crate::{Embed, Itchio, ItchioError, parsers::{date_from_str, option_date_from_str}};

/// The original response this crate gets from the server, useless to crate users.
#[derive(Clone, Debug, Deserialize)] #[allow(dead_code)]
struct WrappedGames {
  games: Vec<Game>,
  page: u16,
  per_page: u16,
}

/// A representation of a publicly visible Game on the itch.io website.
#[derive(Clone, Debug, Deserialize)]
pub struct Game {
  pub id: u32,
  pub title: String,
  pub short_text: Option<String>,
  pub url: Url,
  pub cover_url: Option<Url>,
  pub still_cover_url: Option<Url>,
  pub r#type: String,
  pub classification: String,
  pub p_linux: bool,
  pub p_android: bool,
  pub p_windows: bool,
  pub p_osx: bool,
  #[serde(deserialize_with = "date_from_str")]
  pub created_at: DateTime<Utc>,
  pub min_price: u32,
  pub can_be_bought: bool,
  #[serde(default, deserialize_with = "option_date_from_str")]
  pub published_at: Option<DateTime<Utc>>,
  pub has_demo: bool,
  pub embed: Option<Embed>,
  pub in_press_system: bool,
}

impl Itchio {
  /// Perform a text search for published (and non-deindexed) games.
  pub async fn search_games(&self, query: &str, page: u16) -> Result<Vec<Game>, ItchioError> {
    let endpoint = format!("search/games?query={}&page={}", query, page);
    let response = self.request::<WrappedGames>(endpoint).await?;
    Ok(response.games)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::env;
  use dotenv::dotenv;

  #[tokio::test]
  async fn good() {
    dotenv().ok();
    let client_secret = env::var("KEY").expect("KEY has to be set");
    let api = Itchio::new(client_secret).unwrap();
    let search = api.search_games("a", 1).await.inspect_err(|err| eprintln!("Error spotted: {}", err));
    assert!(search.is_ok())
  }

  #[tokio::test]
  async fn bad_key() {
    let api = Itchio::new("bad_key".to_string()).unwrap();
    let search = api.search_games("a", 1).await;
    assert!(search.is_err_and(|err| matches!(err, ItchioError::BadKey)))
  }
}