rok-cli 0.3.2

Developer CLI for rok-based Axum applications
use super::{write_file, Scaffold, ScaffoldArgs, ScaffoldResult};
use anyhow::Result;

pub struct ApiVersionedScaffold;

impl Scaffold for ApiVersionedScaffold {
    fn name(&self) -> &'static str {
        "api-versioned"
    }
    fn description(&self) -> &'static str {
        "API versioning: v1/v2 modules, version resolver middleware, deprecation headers"
    }

    fn generate(&self, args: &ScaffoldArgs) -> Result<ScaffoldResult> {
        let mut r = ScaffoldResult::default();
        let d = args.dry_run;
        write_file(&mut r, "src/app/controllers/v1/mod.rs", V1_MOD, d)?;
        write_file(&mut r, "src/app/controllers/v2/mod.rs", V2_MOD, d)?;
        write_file(
            &mut r,
            "src/app/middleware/version_resolver.rs",
            VERSION_MW,
            d,
        )?;
        write_file(&mut r, "CHANGELOG.md", CHANGELOG, d)?;
        r.warnings
            .push("Register /v1/* and /v2/* routes in src/app/routes.rs".into());
        Ok(r)
    }
}

const V1_MOD: &str = r#"//! API v1 controllers.
pub mod users;
"#;

const V2_MOD: &str = r#"//! API v2 controllers.
// v2 extends v1 with pagination and additional fields.
pub mod users;
"#;

const VERSION_MW: &str = r#"use axum::{extract::Request, middleware::Next, response::Response};

pub async fn version_resolver(mut req: Request, next: Next) -> Response {
    // TODO: detect version from Accept header (application/vnd.api+json;version=2)
    // or URL prefix (/v1/, /v2/) and store in extensions
    let mut resp = next.run(req).await;
    // Add deprecation headers for v1
    // resp.headers_mut().insert("Deprecation", ...);
    resp
}
"#;

const CHANGELOG: &str = r#"# API Changelog

## v2 (current)
- Added pagination metadata to all list endpoints
- Added `include` parameter for eager-loading relations
- Deprecated: `/v1/users` — use `/v2/users`

## v1 (deprecated, sunset: 2027-01-01)
- Initial public API release
"#;