use kit::{handler, request, json_response, Request, Response};
use kit::database::{Model, ModelMut};
use crate::models::todos::{Entity as Todos, ActiveModel, Model as Todo};
use sea_orm::ActiveValue::Set;
// Request struct for creating todos with validation
#[request]
pub struct CreateTodoRequest {
#[validate(length(min = 1, max = 255, message = "Title is required"))]
pub title: String,
#[validate(length(max = 1000))]
pub description: Option<String>,
}
// Request struct for updating todos with validation
#[request]
pub struct UpdateTodoRequest {
#[validate(length(min = 1, max = 255))]
pub title: Option<String>,
#[validate(length(max = 1000))]
pub description: Option<String>,
pub completed: Option<bool>,
}
// GET /api/todos
#[handler]
pub async fn index(_req: Request) -> Response {
match Todos::all().await {
Ok(todos) => json_response!({
"data": todos,
"count": todos.len()
}),
Err(e) => json_response!({
"error": e.to_string()
}, 500),
}
}
// GET /api/todos/{todo} - Route model binding automatically fetches the todo
#[handler]
pub async fn show(todo: Todo) -> Response {
json_response!({"data": todo})
}
// POST /api/todos
#[handler]
pub async fn store(form: CreateTodoRequest) -> Response {
// `form` is already validated - returns 422 with errors if invalid
let now = chrono::Utc::now().naive_utc();
let new_todo = ActiveModel {
title: Set(form.title),
description: Set(form.description),
completed: Set(false),
created_at: Set(now),
updated_at: Set(now),
..Default::default()
};
match Todos::insert_one(new_todo).await {
Ok(result) => json_response!({
"message": "Todo created",
"id": result.last_insert_id
}, 201),
Err(e) => json_response!({"error": e.to_string()}, 500),
}
}
// PUT /api/todos/{todo} - Route model binding automatically fetches the todo
#[handler]
pub async fn update(todo: Todo, form: UpdateTodoRequest) -> Response {
let mut active: ActiveModel = todo.into();
if let Some(title) = form.title {
active.title = Set(title);
}
if let Some(description) = form.description {
active.description = Set(Some(description));
}
if let Some(completed) = form.completed {
active.completed = Set(completed);
}
active.updated_at = Set(chrono::Utc::now().naive_utc());
match Todos::update_one(active).await {
Ok(updated) => json_response!({"data": updated}),
Err(e) => json_response!({"error": e.to_string()}, 500),
}
}
// DELETE /api/todos/{todo} - Route model binding automatically fetches the todo
#[handler]
pub async fn destroy(todo: Todo) -> Response {
match Todos::delete_by_pk(todo.id).await {
Ok(_) => json_response!({"message": "Todo deleted"}),
Err(e) => json_response!({"error": e.to_string()}, 500),
}
}