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
"#;