athena_rs 0.77.0

WIP Database API gateway
Documentation
//! API Registry endpoints.
//!
//! Lists available APIs and fetches registry entries by id, with simple caching.

use actix_web::{HttpRequest, Responder, get, web::Data};
use serde_json::Value;
// use tracing::info;

// crate imports
use crate::AppState;
use crate::api::response::{api_ok, internal_error};
use crate::data::api_registry::{get_api_registry_by_id, list_api_registry_entries};

#[get("/registry")]
/// List all API registry entries.
async fn api_registry(req: HttpRequest, app_state: Data<AppState>) -> impl Responder {
    let cache_key = "api_registry_list".to_string();

    // Check for cache-control no-cache header
    let should_bypass_cache = req
        .headers()
        .get("cache-control")
        .and_then(|h| h.to_str().ok())
        .map(|s| s.contains("no-cache"))
        .unwrap_or(false);

    if should_bypass_cache {
        app_state.cache.invalidate(&cache_key).await;
    }

    // Try to get from cache first
    if let Some(cached_entries) = app_state.cache.get(&cache_key).await {
        return api_ok(cached_entries);
    }

    // If not in cache, fetch from database
    match list_api_registry_entries().await {
        Ok(entries) => {
            let entries_value = serde_json::to_value(&entries).unwrap_or(Value::Null);
            app_state
                .cache
                .insert(cache_key, entries_value.clone())
                .await;
            api_ok(entries)
        }
        Err(err) => internal_error("Failed to list API registry entries", err),
    }
}

#[get("/registry/{api_registry_id}")]
/// Get a single API registry entry by id.
async fn api_registry_by_id(
    path: actix_web::web::Path<String>,
    req: HttpRequest,
    app_state: Data<AppState>,
) -> impl Responder {
    let api_registry_id = path.into_inner();
    let cache_key = format!("api_registry_{}", api_registry_id);

    // Check for cache-control no-cache header
    let should_bypass_cache = req
        .headers()
        .get("cache-control")
        .and_then(|h| h.to_str().ok())
        .map(|s| s.contains("no-cache"))
        .unwrap_or(false);

    if should_bypass_cache {
        app_state.cache.invalidate(&cache_key).await;
    }

    // Try to get from cache first
    if let Some(cached_entry) = app_state.cache.get(&cache_key).await {
        return api_ok(cached_entry);
    }

    // If not in cache, fetch from database
    match get_api_registry_by_id(&api_registry_id).await {
        Ok(entry) => {
            let entry_value = serde_json::to_value(&entry).unwrap_or(Value::Null);
            app_state.cache.insert(cache_key, entry_value.clone()).await;
            api_ok(entry)
        }
        Err(err) => internal_error("Failed to get API registry entry", err),
    }
}