bitculator 1.1.0

Official Rust SDK for the Bitculator Data API
Documentation
use std::fmt::Display;
use std::sync::Arc;

use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::{json, Value};

use crate::error::Error;
use crate::http::{enc, HttpClient};
use crate::pagination::Page;
use crate::params::Params;

/// Editorial content: articles, videos, and insights.
pub struct Editorial {
    http: Arc<HttpClient>,
}

impl Editorial {
    pub(crate) fn new(http: Arc<HttpClient>) -> Self {
        Self { http }
    }

    /// Videos for a coin (paginated). Params: page, per_page, type, search.
    pub fn coin_videos<T: DeserializeOwned>(&self, slug: &str, params: Params) -> Result<Page<T>, Error> {
        Page::fetch(self.http.clone(), &format!("/api/v1/coins/{}/videos", enc(slug)), params)
    }

    /// Insight timeline for a coin. Params: locale, offset, limit.
    pub fn coin_insights<T: DeserializeOwned>(&self, slug: &str, params: Params) -> Result<T, Error> {
        self.http.get(&format!("/api/v1/coins/{}/insights", enc(slug)), &params)
    }

    /// List articles (paginated). Params: page, per_page, locale, tag, coin,
    /// exchange, wallet, search.
    pub fn articles<T: DeserializeOwned>(&self, params: Params) -> Result<Page<T>, Error> {
        Page::fetch(self.http.clone(), "/api/v1/articles", params)
    }

    /// Get a single article by slug. Params: locale.
    pub fn article<T: DeserializeOwned>(&self, slug: &str, params: Params) -> Result<T, Error> {
        self.http.get(&format!("/api/v1/articles/{}", enc(slug)), &params)
    }

    /// Submit helpful/unhelpful feedback on an article.
    pub fn submit_article_feedback(&self, slug: &str, helpful: bool) -> Result<Value, Error> {
        self.http.post_value(&format!("/api/v1/articles/{}/feedback", enc(slug)), Some(json!({ "helpful": helpful })))
    }

    /// Get a single video by id.
    pub fn video<T: DeserializeOwned>(&self, id: impl Display) -> Result<T, Error> {
        self.http.get(&format!("/api/v1/videos/{}", enc(&id.to_string())), &Params::new())
    }

    /// List insights (paginated). Params: page, per_page, locale, type, coin, search, sort.
    pub fn insights<T: DeserializeOwned>(&self, params: Params) -> Result<Page<T>, Error> {
        Page::fetch(self.http.clone(), "/api/v1/insights", params)
    }

    /// Get a single insight by id. Params: locale.
    pub fn insight<T: DeserializeOwned>(&self, id: impl Display, params: Params) -> Result<T, Error> {
        self.http.get(&format!("/api/v1/insights/{}", enc(&id.to_string())), &params)
    }
}

/// Body for creating an alarm.
#[derive(Debug, Clone, Serialize)]
pub struct NewAlarm {
    pub name: String,
    pub coin: String,
    pub metric: String,
    pub direction: String,
    pub target: f64,
    pub notification: String,
}

/// Price alarms owned by the API key.
pub struct Alarms {
    http: Arc<HttpClient>,
}

impl Alarms {
    pub(crate) fn new(http: Arc<HttpClient>) -> Self {
        Self { http }
    }

    /// List your alarms (paginated). Params: page, per_page, status, direction, notification.
    pub fn list<T: DeserializeOwned>(&self, params: Params) -> Result<Page<T>, Error> {
        Page::fetch(self.http.clone(), "/api/v1/alarms", params)
    }

    /// Create an alarm.
    pub fn create(&self, alarm: &NewAlarm) -> Result<Value, Error> {
        let body = serde_json::to_value(alarm).map_err(|e| Error::Decode(e.to_string()))?;
        self.http.post_value("/api/v1/alarms", Some(body))
    }

    /// Delete an alarm by id.
    pub fn delete(&self, id: impl Display) -> Result<Value, Error> {
        self.http.delete_value(&format!("/api/v1/alarms/{}", enc(&id.to_string())))
    }
}

/// Body for registering a webhook endpoint.
#[derive(Debug, Clone, Serialize)]
pub struct NewWebhook {
    pub url: String,
    pub events: Vec<String>,
}

/// Webhook endpoints and their delivery log.
pub struct Webhooks {
    http: Arc<HttpClient>,
}

impl Webhooks {
    pub(crate) fn new(http: Arc<HttpClient>) -> Self {
        Self { http }
    }

    /// List your webhook endpoints.
    pub fn list<T: DeserializeOwned>(&self) -> Result<T, Error> {
        self.http.get("/api/v1/webhooks", &Params::new())
    }

    /// Register a webhook endpoint for a set of events.
    pub fn create(&self, webhook: &NewWebhook) -> Result<Value, Error> {
        let body = serde_json::to_value(webhook).map_err(|e| Error::Decode(e.to_string()))?;
        self.http.post_value("/api/v1/webhooks", Some(body))
    }

    /// Delete a webhook endpoint by id.
    pub fn delete(&self, id: impl Display) -> Result<Value, Error> {
        self.http.delete_value(&format!("/api/v1/webhooks/{}", enc(&id.to_string())))
    }

    /// Send a test event to a webhook endpoint.
    pub fn test(&self, id: impl Display) -> Result<Value, Error> {
        self.http.post_value(&format!("/api/v1/webhooks/{}/test", enc(&id.to_string())), None)
    }

    /// Delivery log for a webhook endpoint (paginated). Params: page, per_page.
    pub fn deliveries<T: DeserializeOwned>(&self, id: impl Display, params: Params) -> Result<Page<T>, Error> {
        Page::fetch(self.http.clone(), &format!("/api/v1/webhooks/{}/deliveries", enc(&id.to_string())), params)
    }
}

/// Service metadata: spec, health, and key usage.
pub struct Meta {
    http: Arc<HttpClient>,
}

impl Meta {
    pub(crate) fn new(http: Arc<HttpClient>) -> Self {
        Self { http }
    }

    /// The raw OpenAPI specification for the API.
    pub fn openapi<T: DeserializeOwned>(&self) -> Result<T, Error> {
        self.http.get("/api/v1/openapi.json", &Params::new())
    }

    /// Health check.
    pub fn ping<T: DeserializeOwned>(&self) -> Result<T, Error> {
        self.http.get("/api/v1/ping", &Params::new())
    }

    /// Current key usage and quota.
    pub fn usage<T: DeserializeOwned>(&self) -> Result<T, Error> {
        self.http.get("/api/v1/usage", &Params::new())
    }
}