use crate::{anthropic_request_json, ApiResponseOrError, Credentials};
use derive_builder::Builder;
use reqwest::Method;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ApiKeyStatus {
Active,
Inactive,
Archived,
}
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct ApiKeyCreator {
pub id: String,
#[serde(rename = "type")]
pub creator_type: String,
}
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct ApiKey {
pub id: String,
pub name: String,
pub created_at: String,
pub created_by: ApiKeyCreator,
pub partial_key_hint: Option<String>,
pub status: ApiKeyStatus,
#[serde(rename = "type")]
pub key_type: String,
pub workspace_id: Option<String>,
}
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct ApiKeyList {
pub data: Vec<ApiKey>,
pub first_id: Option<String>,
pub last_id: Option<String>,
pub has_more: bool,
}
#[derive(Serialize, Builder, Debug, Clone)]
#[builder(derive(Clone, Debug, PartialEq))]
#[builder(pattern = "owned")]
#[builder(name = "ApiKeyListBuilder")]
#[builder(setter(strip_option, into))]
pub struct ApiKeyListRequest {
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub before_id: Option<String>,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub after_id: Option<String>,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<ApiKeyStatus>,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub workspace_id: Option<String>,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub created_by_user_id: Option<String>,
#[serde(skip_serializing)]
#[builder(default)]
pub credentials: Option<Credentials>,
}
#[derive(Serialize, Builder, Debug, Clone)]
#[builder(derive(Clone, Debug, PartialEq))]
#[builder(pattern = "owned")]
#[builder(name = "ApiKeyBuilder")]
#[builder(setter(strip_option, into))]
pub struct ApiKeyRequest {
pub api_key_id: String,
#[serde(skip_serializing)]
#[builder(default)]
pub credentials: Option<Credentials>,
}
#[derive(Serialize, Builder, Debug, Clone)]
#[builder(derive(Clone, Debug, PartialEq))]
#[builder(pattern = "owned")]
#[builder(name = "ApiKeyUpdateBuilder")]
#[builder(setter(strip_option, into))]
pub struct ApiKeyUpdateRequest {
#[serde(skip_serializing)]
pub api_key_id: String,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<ApiKeyStatus>,
#[serde(skip_serializing)]
#[builder(default)]
pub credentials: Option<Credentials>,
}
impl ApiKeyList {
pub fn builder() -> ApiKeyListBuilder {
ApiKeyListBuilder::create_empty()
}
pub async fn create(request: ApiKeyListRequest) -> ApiResponseOrError<Self> {
let credentials_opt = request.credentials.clone();
let mut query_params = Vec::new();
if let Some(before_id) = &request.before_id {
query_params.push(("before_id", before_id.clone()));
}
if let Some(after_id) = &request.after_id {
query_params.push(("after_id", after_id.clone()));
}
if let Some(limit) = request.limit {
query_params.push(("limit", limit.to_string()));
}
if let Some(status) = &request.status {
query_params.push(("status", format!("{:?}", status).to_lowercase()));
}
if let Some(workspace_id) = &request.workspace_id {
query_params.push(("workspace_id", workspace_id.clone()));
}
if let Some(created_by_user_id) = &request.created_by_user_id {
query_params.push(("created_by_user_id", created_by_user_id.clone()));
}
anthropic_request_json(
Method::GET,
"organizations/api_keys",
|r| r.query(&query_params),
credentials_opt,
)
.await
}
}
impl ApiKey {
pub fn builder(api_key_id: impl Into<String>) -> ApiKeyBuilder {
ApiKeyBuilder::create_empty().api_key_id(api_key_id)
}
pub async fn create(request: ApiKeyRequest) -> ApiResponseOrError<Self> {
let credentials_opt = request.credentials.clone();
let route = format!("organizations/api_keys/{}", request.api_key_id);
anthropic_request_json(Method::GET, &route, |r| r, credentials_opt).await
}
pub fn update_builder(api_key_id: impl Into<String>) -> ApiKeyUpdateBuilder {
ApiKeyUpdateBuilder::create_empty().api_key_id(api_key_id)
}
pub async fn update(request: ApiKeyUpdateRequest) -> ApiResponseOrError<Self> {
let credentials_opt = request.credentials.clone();
let route = format!("organizations/api_keys/{}", request.api_key_id);
anthropic_request_json(Method::POST, &route, |r| r.json(&request), credentials_opt).await
}
}
impl ApiKeyListBuilder {
pub async fn create(self) -> ApiResponseOrError<ApiKeyList> {
let request = self.build().unwrap();
ApiKeyList::create(request).await
}
}
impl ApiKeyBuilder {
pub async fn create(self) -> ApiResponseOrError<ApiKey> {
let request = self.build().unwrap();
ApiKey::create(request).await
}
}
impl ApiKeyUpdateBuilder {
pub async fn create(self) -> ApiResponseOrError<ApiKey> {
let request = self.build().unwrap();
ApiKey::update(request).await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Credentials;
#[tokio::test]
#[ignore] async fn test_list_api_keys() {
let credentials = Credentials::from_env();
let api_keys = ApiKeyList::builder()
.credentials(credentials)
.create()
.await
.unwrap();
assert!(api_keys.data.len() > 0);
}
#[tokio::test]
#[ignore] async fn test_get_api_key() {
let credentials = Credentials::from_env();
let api_keys = ApiKeyList::builder()
.credentials(credentials.clone())
.create()
.await
.unwrap();
if let Some(api_key) = api_keys.data.first() {
let api_key_id = &api_key.id;
let api_key_details = ApiKey::builder(api_key_id)
.credentials(credentials)
.create()
.await
.unwrap();
assert_eq!(api_key_details.id, *api_key_id);
}
}
}