openrouter-rs 0.5.2

A type-safe OpenRouter Rust SDK
Documentation
use serde::{Deserialize, Serialize};
use surf::http::headers::AUTHORIZATION;

use crate::{
    error::OpenRouterError,
    types::{ApiResponse, PaginationOptions},
    utils::handle_error,
};

#[derive(Serialize, Deserialize, Debug)]
pub struct ApiKey {
    pub name: Option<String>,
    pub label: Option<String>,
    pub limit: Option<f64>,
    pub disabled: Option<bool>,
    pub created_at: Option<String>,
    pub updated_at: Option<String>,
    pub hash: Option<String>,
    pub key: Option<String>,
}

#[derive(Serialize, Debug)]
pub struct ApiKeyDetails {
    pub label: String,
    pub usage: f64,
    pub is_free_tier: bool,
    pub is_management_key: bool,
    pub rate_limit: RateLimit,
    pub limit: Option<f64>,
    pub limit_remaining: Option<f64>,
}

#[derive(Deserialize)]
struct ApiKeyDetailsWire {
    label: String,
    usage: f64,
    is_free_tier: bool,
    #[serde(default)]
    is_management_key: Option<bool>,
    #[serde(default)]
    is_provisioning_key: Option<bool>,
    rate_limit: RateLimit,
    limit: Option<f64>,
    limit_remaining: Option<f64>,
}

impl<'de> Deserialize<'de> for ApiKeyDetails {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let wire = ApiKeyDetailsWire::deserialize(deserializer)?;
        Ok(Self {
            label: wire.label,
            usage: wire.usage,
            is_free_tier: wire.is_free_tier,
            is_management_key: wire
                .is_management_key
                .or(wire.is_provisioning_key)
                .unwrap_or(false),
            rate_limit: wire.rate_limit,
            limit: wire.limit,
            limit_remaining: wire.limit_remaining,
        })
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RateLimit {
    pub requests: f64,
    pub interval: String,
}

#[derive(Serialize)]
struct CreateApiKeyRequest {
    name: String,
    limit: Option<f64>,
}

#[derive(Serialize)]
struct UpdateApiKeyRequest {
    name: Option<String>,
    disabled: Option<bool>,
    limit: Option<f64>,
}

#[derive(Serialize)]
struct ListApiKeysQuery {
    #[serde(skip_serializing_if = "Option::is_none")]
    offset: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    include_disabled: Option<bool>,
}

/// Get information on the API key associated with the current authentication session
///
/// # Arguments
///
/// * `base_url` - The base URL of the OpenRouter API.
/// * `api_key` - The API key for authentication.
///
/// # Returns
///
/// * `Result<ApiKeyDetails, OpenRouterError>` - The details of the current API key.
pub async fn get_current_api_key(
    base_url: &str,
    api_key: &str,
) -> Result<ApiKeyDetails, OpenRouterError> {
    let url = format!("{base_url}/key");

    let mut response = surf::get(url)
        .header(AUTHORIZATION, format!("Bearer {api_key}"))
        .send()
        .await?;

    if response.status().is_success() {
        let api_response: ApiResponse<_> = response.body_json().await?;
        Ok(api_response.data)
    } else {
        handle_error(response).await?;
        unreachable!()
    }
}

/// Returns a list of all API keys associated with the account. Requires a management API key.
///
/// # Arguments
///
/// * `base_url` - The base URL of the OpenRouter API.
/// * `management_key` - The management API key for authentication.
/// * `pagination` - Optional pagination options for the API keys list.
/// * `include_disabled` - Optional flag to include disabled API keys.
///
/// # Returns
///
/// * `Result<Vec<ApiKey>, OpenRouterError>` - A list of API keys.
pub async fn list_api_keys(
    base_url: &str,
    management_key: &str,
    pagination: Option<PaginationOptions>,
    include_disabled: Option<bool>,
) -> Result<Vec<ApiKey>, OpenRouterError> {
    let url = format!("{base_url}/keys");
    let query = ListApiKeysQuery {
        offset: pagination.and_then(|p| p.offset),
        include_disabled,
    };
    let req = surf::get(url).header(AUTHORIZATION, format!("Bearer {management_key}"));
    let mut response = if query.offset.is_none() && query.include_disabled.is_none() {
        req.await?
    } else {
        req.query(&query)?.await?
    };

    if response.status().is_success() {
        let api_response: ApiResponse<_> = response.body_json().await?;
        Ok(api_response.data)
    } else {
        handle_error(response).await?;
        unreachable!()
    }
}

/// Creates a new API key. Requires a management API key.
///
/// # Arguments
///
/// * `base_url` - The base URL of the OpenRouter API.
/// * `management_key` - The management API key for authentication.
/// * `name` - The display name for the new API key.
/// * `limit` - Optional credit limit for the new API key.
///
/// # Returns
///
/// * `Result<ApiKey, OpenRouterError>` - The created API key.
pub async fn create_api_key(
    base_url: &str,
    management_key: &str,
    name: &str,
    limit: Option<f64>,
) -> Result<ApiKey, OpenRouterError> {
    let url = format!("{base_url}/keys");
    let request = CreateApiKeyRequest {
        name: name.to_string(),
        limit,
    };

    let mut response = surf::post(url)
        .header(AUTHORIZATION, format!("Bearer {management_key}"))
        .body_json(&request)?
        .await?;

    if response.status().is_success() {
        let api_response: ApiResponse<_> = response.body_json().await?;
        Ok(api_response.data)
    } else {
        handle_error(response).await?;
        unreachable!()
    }
}

/// Returns details about a specific API key. Requires a management API key.
///
/// # Arguments
///
/// * `base_url` - The base URL of the OpenRouter API.
/// * `management_key` - The management API key for authentication.
/// * `hash` - The hash of the API key to retrieve.
///
/// # Returns
///
/// * `Result<ApiKey, OpenRouterError>` - The details of the specified API key.
pub async fn get_api_key(
    base_url: &str,
    management_key: &str,
    hash: &str,
) -> Result<ApiKey, OpenRouterError> {
    let url = format!("{base_url}/keys/{hash}");

    let mut response = surf::get(&url)
        .header(AUTHORIZATION, format!("Bearer {management_key}"))
        .await?;

    if response.status().is_success() {
        let api_response: ApiResponse<_> = response.body_json().await?;
        Ok(api_response.data)
    } else {
        handle_error(response).await?;
        unreachable!()
    }
}

/// Deletes an API key. Requires a management API key.
///
/// # Arguments
///
/// * `base_url` - The base URL of the OpenRouter API.
/// * `management_key` - The management API key for authentication.
/// * `hash` - The hash of the API key to delete.
///
/// # Returns
///
/// * `Result<bool, OpenRouterError>` - A boolean indicating whether the deletion was successful.
pub async fn delete_api_key(
    base_url: &str,
    management_key: &str,
    hash: &str,
) -> Result<bool, OpenRouterError> {
    let url = format!("{base_url}/keys/{hash}");

    let response = surf::delete(&url)
        .header(AUTHORIZATION, format!("Bearer {management_key}"))
        .await?;

    if response.status().is_success() {
        Ok(true)
    } else {
        handle_error(response).await?;
        unreachable!()
    }
}

/// Updates an existing API key. Requires a management API key.
///
/// # Arguments
///
/// * `base_url` - The base URL of the OpenRouter API.
/// * `management_key` - The management API key for authentication.
/// * `hash` - The hash of the API key to update.
/// * `name` - Optional new display name for the API key.
/// * `disabled` - Optional flag to disable the API key.
/// * `limit` - Optional new credit limit for the API key.
///
/// # Returns
///
/// * `Result<ApiKey, OpenRouterError>` - The updated API key.
pub async fn update_api_key(
    base_url: &str,
    management_key: &str,
    hash: &str,
    name: Option<String>,
    disabled: Option<bool>,
    limit: Option<f64>,
) -> Result<ApiKey, OpenRouterError> {
    let url = format!("{base_url}/keys/{hash}");
    let request = UpdateApiKeyRequest {
        name,
        disabled,
        limit,
    };

    let mut response = surf::patch(&url)
        .header(AUTHORIZATION, format!("Bearer {management_key}"))
        .body_json(&request)?
        .await?;

    if response.status().is_success() {
        let api_response: ApiResponse<_> = response.body_json().await?;
        Ok(api_response.data)
    } else {
        handle_error(response).await?;
        unreachable!()
    }
}