puerto 0.19.0

Puerto — Rust full-stack DDD framework CLI. Scaffolds Clean Architecture projects with auto-wired DI, SQLx support, and zero manual wiring. Formerly puerto-framework.
// AUTO-GENERATED by puerto. Edit puerto.toml, then run `puerto generate bootstrap`.
use std::sync::Arc;

use business::application::greeting::get_greeting::GetGreetingUseCaseImpl;

use business::domain::greeting::repository::GreetingRepositoryTrait;
use infrastructure::greeting::repository::InMemoryGreetingRepository;

use poem::Endpoint;
use poem_openapi::OpenApiService;

use crate::api::greeting::routes::GreetingApi;

/// The routes, wired. An error is what stopped the startup: `main` prints it and exits 1.
pub async fn build_app(config: puerto_web::Config) -> Result<impl Endpoint, String> {
    let get_greeting = Arc::new(GetGreetingUseCaseImpl { repository: Arc::new(InMemoryGreetingRepository::new()) as Arc<dyn GreetingRepositoryTrait> });
    let greeting_api = GreetingApi { get_greeting };

    let ready = puerto_web::health::always_ready();

    // `app.rs` is the project's own: middleware and routes added there wrap everything here.
    Ok(crate::app::configure(puerto_web::routes(
        openapi_service(greeting_api),
        &config,
        ready,
    )))
}

/// The API service, built in one place: whatever else reads its spec (the export test of a project
/// with `web/`) sees the API the server answers.
fn openapi_service<T: poem_openapi::OpenApi>(api: T) -> OpenApiService<T, ()> {
    OpenApiService::new(api, env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"))
}

#[cfg(test)]
mod tests {
    use super::*;

    use business::domain::greeting::use_cases::get_greeting::mocks::MockGetGreetingUseCase;

    /// The API contract the frontend's types are generated from (`make web/sync`).
    const OPENAPI_JSON: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docs/api/openapi.json");

    /// Built from mocked use cases: no server, no database. A missing file is written; a different
    /// one fails — run `make web/sync` (it sets `UPDATE_OPENAPI=1`) and commit the diff.
    #[test]
    fn openapi_spec_matches_docs_api_openapi_json() {
        let greeting_api = GreetingApi { get_greeting: Arc::new(MockGetGreetingUseCase::new()) };
        let spec = openapi_service(greeting_api).spec();

        let path = std::path::Path::new(OPENAPI_JSON);
        if std::env::var_os("UPDATE_OPENAPI").is_some() || !path.exists() {
            let dir = path.parent().expect("docs/api/openapi.json has a parent");
            std::fs::create_dir_all(dir).expect("create docs/api");
            std::fs::write(path, &spec).expect("write docs/api/openapi.json");
            return;
        }
        let committed = std::fs::read_to_string(path).expect("read docs/api/openapi.json");
        assert!(
            committed == spec,
            "docs/api/openapi.json is not the API this code serves: run `make web/sync`"
        );
    }
}