genome-sh 0.1.0

The jq of genomics. Fast, local, human-readable variant analysis.
mod gnomad;
mod routes;

use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;

use anyhow::{Context, Result};
use axum::Router;
use tower_http::cors::CorsLayer;
use tower_http::trace::TraceLayer;

use crate::db::Database;

/// Shared state for API handlers.
pub struct AppState {
    pub db: Database,
    pub gnomad_client: gnomad::GnomadClient,
}

/// Start the API server.
pub async fn serve(db_path: PathBuf, host: &str, port: u16) -> Result<()> {
    let db = Database::open_at(&db_path)
        .with_context(|| format!("Failed to open database at {}", db_path.display()))?;

    let state = Arc::new(AppState {
        db,
        gnomad_client: gnomad::GnomadClient::new(),
    });

    let app = Router::new()
        .merge(routes::router())
        .layer(CorsLayer::permissive())
        .layer(TraceLayer::new_for_http())
        .with_state(state);

    let addr: SocketAddr = format!("{host}:{port}")
        .parse()
        .context("Invalid address")?;

    tracing::info!("API server listening on {addr}");
    println!("genome-sh API server running at http://{addr}");
    println!("Try: curl http://{addr}/v1/query/rs80357906");

    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app).await?;

    Ok(())
}