puerto 0.10.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.
use std::sync::Arc;

use business::{
    application::{{ snake }}::{
        create_{{ snake }}::Create{{ pascal }}UseCaseImpl,
        delete_{{ snake }}::Delete{{ pascal }}UseCaseImpl,
        get_{{ snake }}::Get{{ pascal }}UseCaseImpl,
        list_{{ snake }}::List{{ pascal }}UseCaseImpl,
        update_{{ snake }}::Update{{ pascal }}UseCaseImpl,
    },
    domain::{{ snake }}::use_cases::{
        create_{{ snake }}::{Create{{ pascal }}Params, Create{{ pascal }}UseCaseTrait},
        delete_{{ snake }}::{Delete{{ pascal }}Params, Delete{{ pascal }}UseCaseTrait},
        get_{{ snake }}::{Get{{ pascal }}Params, Get{{ pascal }}UseCaseTrait},
        list_{{ snake }}::{List{{ pascal }}Params, List{{ pascal }}UseCaseTrait},
        update_{{ snake }}::{Update{{ pascal }}Params, Update{{ pascal }}UseCaseTrait},
    },
};
use poem_openapi::{OpenApi, param::Path, payload::Json};
use uuid::Uuid;

use crate::api::error::IntoErrorResponse;
use crate::api::tags::ApiTags;
use crate::api::{{ snake }}::dto::{Create{{ pascal }}Request, Update{{ pascal }}Request, {{ pascal }}Dto};
use crate::api::{{ snake }}::responses::{
    Create{{ pascal }}Response, Delete{{ pascal }}Response, Get{{ pascal }}Response, List{{ pascal }}Response,
    Update{{ pascal }}Response,
};

pub struct {{ pascal }}Api {
    pub create_{{ snake }}: Arc<Create{{ pascal }}UseCaseImpl>,
    pub get_{{ snake }}: Arc<Get{{ pascal }}UseCaseImpl>,
    pub list_{{ snake }}: Arc<List{{ pascal }}UseCaseImpl>,
    pub update_{{ snake }}: Arc<Update{{ pascal }}UseCaseImpl>,
    pub delete_{{ snake }}: Arc<Delete{{ pascal }}UseCaseImpl>,
}

#[OpenApi]
impl {{ pascal }}Api {
    /// Create a new {{ pascal }}
    #[oai(path = "/{{ snake }}s", method = "post", tag = "ApiTags::{{ pascal }}")]
    async fn create(&self, body: Json<Create{{ pascal }}Request>) -> Create{{ pascal }}Response {
        match self
            .create_{{ snake }}
            .execute(Create{{ pascal }}Params {
{{ create_params_str }}
            })
            .await
        {
            Ok(entity) => Create{{ pascal }}Response::Created(Json({{ pascal }}Dto::from_domain(&entity))),
            Err(err) => {
                let (status, error) = err.into_error_response();
                tracing::warn!(code = %error.0.name, "create_{{ snake }} failed");
                Create{{ pascal }}Response::from_status(status, error)
            }
        }
    }

    /// Get a {{ pascal }} by ID
    #[oai(path = "/{{ snake }}s/:id", method = "get", tag = "ApiTags::{{ pascal }}")]
    async fn get_by_id(&self, id: Path<Uuid>) -> Get{{ pascal }}Response {
        match self
            .get_{{ snake }}
            .execute(Get{{ pascal }}Params { id: id.0 })
            .await
        {
            Ok(entity) => Get{{ pascal }}Response::Ok(Json({{ pascal }}Dto::from_domain(&entity))),
            Err(err) => {
                let (status, error) = err.into_error_response();
                tracing::warn!(code = %error.0.name, "get_{{ snake }} failed");
                Get{{ pascal }}Response::from_status(status, error)
            }
        }
    }

    /// List all {{ pascal }}s
    #[oai(path = "/{{ snake }}s", method = "get", tag = "ApiTags::{{ pascal }}")]
    async fn list(&self) -> List{{ pascal }}Response {
        match self.list_{{ snake }}.execute(List{{ pascal }}Params).await {
            Ok(entities) => {
                List{{ pascal }}Response::Ok(Json(entities.iter().map({{ pascal }}Dto::from_domain).collect()))
            }
            Err(err) => {
                let (status, error) = err.into_error_response();
                tracing::error!(code = %error.0.name, "list_{{ snake }} failed");
                List{{ pascal }}Response::from_status(status, error)
            }
        }
    }

    /// Update a {{ pascal }}
    #[oai(path = "/{{ snake }}s/:id", method = "put", tag = "ApiTags::{{ pascal }}")]
    async fn update(&self, id: Path<Uuid>, body: Json<Update{{ pascal }}Request>) -> Update{{ pascal }}Response {
        match self
            .update_{{ snake }}
            .execute(Update{{ pascal }}Params {
{{ update_params_str }}
            })
            .await
        {
            Ok(entity) => Update{{ pascal }}Response::Ok(Json({{ pascal }}Dto::from_domain(&entity))),
            Err(err) => {
                let (status, error) = err.into_error_response();
                tracing::warn!(code = %error.0.name, "update_{{ snake }} failed");
                Update{{ pascal }}Response::from_status(status, error)
            }
        }
    }

    /// Delete a {{ pascal }}
    #[oai(path = "/{{ snake }}s/:id", method = "delete", tag = "ApiTags::{{ pascal }}")]
    async fn delete(&self, id: Path<Uuid>) -> Delete{{ pascal }}Response {
        match self
            .delete_{{ snake }}
            .execute(Delete{{ pascal }}Params { id: id.0 })
            .await
        {
            Ok(()) => Delete{{ pascal }}Response::NoContent,
            Err(err) => {
                let (status, error) = err.into_error_response();
                tracing::warn!(code = %error.0.name, "delete_{{ snake }} failed");
                Delete{{ pascal }}Response::from_status(status, error)
            }
        }
    }
}