routa-server 0.16.0

Routa.js HTTP Server — axum adapter on top of routa-core
Documentation
use std::fs;
use std::path::PathBuf;
use std::time::Duration;

use reqwest::{Client, StatusCode};
use routa_server::{start_server, ServerConfig};

pub struct ApiFixture {
    pub base_url: String,
    pub client: Client,
    pub db_path: PathBuf,
}

impl ApiFixture {
    pub async fn new() -> Self {
        let db_path = random_db_path();
        let config = ServerConfig {
            host: "127.0.0.1".to_string(),
            port: 0,
            db_path: db_path.to_string_lossy().to_string(),
            static_dir: None,
        };

        let addr = start_server(config)
            .await
            .expect("start server for api fixture");
        let fixture = Self {
            base_url: format!("http://{addr}"),
            client: Client::new(),
            db_path,
        };
        fixture.wait_until_ready().await;
        fixture
    }

    pub fn endpoint(&self, path: &str) -> String {
        format!("{}{}", self.base_url, path)
    }

    pub async fn wait_until_ready(&self) {
        for _ in 0..50 {
            if self
                .client
                .get(self.endpoint("/api/health"))
                .send()
                .await
                .is_ok_and(|resp| resp.status() == StatusCode::OK)
            {
                return;
            }
            tokio::time::sleep(Duration::from_millis(20)).await;
        }
        panic!("server did not become ready");
    }
}

impl Drop for ApiFixture {
    fn drop(&mut self) {
        let _ = fs::remove_file(&self.db_path);
    }
}

pub fn random_db_path() -> PathBuf {
    std::env::temp_dir().join(format!("routa-server-api-{}.db", uuid::Uuid::new_v4()))
}