puerto 0.11.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`.
{% if entities -%}
use std::sync::Arc;

{% for entity in entities -%}
{% for uc in entity.use_cases -%}
use business::application::{{ entity.snake }}::{{ uc.action }}::{{ uc.uc_pascal }}UseCaseImpl;
{% endfor -%}
{% endfor %}
{% for entity in entities -%}
use business::domain::{{ entity.snake }}::repository::{{ entity.pascal }}RepositoryTrait;
use infrastructure::{{ entity.snake }}::repository::{% if entity.db %}Pg{% else %}InMemory{% endif %}{{ entity.pascal }}Repository;
{% endfor %}
{% endif -%}
use poem::{EndpointExt, Route, get, middleware::{Cors, Tracing}};
use poem_openapi::OpenApiService;

{% for entity in entities -%}
use crate::api::{{ entity.snake }}::routes::{{ entity.pascal }}Api;
{% endfor %}
pub async fn build_app() -> impl poem::Endpoint {
{%- if has_db %}
    let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let pool = infrastructure::db::create_postgres_pool(&database_url)
        .await
        .expect("Failed to connect to database");
    infrastructure::db::run_migrations(&pool)
        .await
        .expect("Failed to run migrations");
{% endif %}
{%- for entity in entities %}
{%- if entity.db %}{% set repo = "Pg" ~ entity.pascal ~ "Repository::new(pool.clone())" %}{% else %}{% set repo = "InMemory" ~ entity.pascal ~ "Repository::new()" %}{% endif %}
{%- if entity.use_cases | length > 1 %}
    let {{ entity.snake }}_repo: Arc<dyn {{ entity.pascal }}RepositoryTrait> = Arc::new({{ repo }});
{%- endif %}
{%- for uc in entity.use_cases %}
    let {{ uc.action }} = Arc::new({{ uc.uc_pascal }}UseCaseImpl { repository: {% if entity.use_cases | length == 1 %}Arc::new({{ repo }}) as Arc<dyn {{ entity.pascal }}RepositoryTrait>{% elif loop.last %}{{ entity.snake }}_repo{% else %}Arc::clone(&{{ entity.snake }}_repo){% endif %} });
{%- endfor %}
    let {{ entity.snake }}_api = {{ entity.pascal }}Api {% if entity.use_cases %}{ {% for uc in entity.use_cases %}{{ uc.action }}{% if not loop.last %}, {% endif %}{% endfor %} }{% else %}{}{% endif %};
{% endfor %}
    let port = std::env::var("SERVICE_PORT").unwrap_or_else(|_| "8080".to_string());
    let api_service = OpenApiService::new(
        {% if entities | length == 1 %}{{ entities.0.snake }}_api{% else %}({% for entity in entities %}{{ entity.snake }}_api{% if not loop.last %}, {% endif %}{% endfor %}){% endif %},
        env!("CARGO_PKG_NAME"),
        env!("CARGO_PKG_VERSION"),
    )
    .server(format!("http://localhost:{port}/api"));
    let ui = api_service.swagger_ui();

    let cors_origins = std::env::var("CORS_ALLOWED_ORIGINS").unwrap_or_default();
    let mut cors = Cors::new();
    for origin in cors_origins.split(',').map(str::trim).filter(|s| !s.is_empty()) {
        cors = cors.allow_origin(origin);
    }

    Route::new()
        .at("/health", get(crate::health::liveness))
{%- if has_db %}
        .at(
            "/health/ready",
            get(poem::endpoint::make(move |_| {
                let pool = pool.clone();
                async move { crate::health::readiness(infrastructure::db::ping(&pool).await) }
            })),
        )
{%- else %}
        .at(
            "/health/ready",
            get(poem::endpoint::make_sync(|_| crate::health::readiness(true))),
        )
{%- endif %}
        .nest("/api", api_service)
        .nest("/", ui)
        .with(Tracing)
        .with(cors)
}