This guide walks you through the standard process of adding a new feature to RustAPI using the Action pattern.
- You have the repo cloned.
- You understand the Action Pattern.
Create a new file in the appropriate crate (or crates/rustapi-core/src/actions/ if it's core).
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
pub struct CreateWidget {
pub name: String,
pub quantity: i32,
}Implement the logic trait.
impl Action for CreateWidget {
type Output = Widget;
type Error = ApiError;
async fn run(&self, ctx: &Context) -> Result<Self::Output, Self::Error> {
// Validation
if self.quantity < 0 {
return Err(ApiError::BadRequest("Quantity must be positive"));
}
// Database
let widget = sqlx::query_as!(
Widget,
"INSERT INTO widgets (name, quantity) VALUES ($1, $2) RETURNING *",
self.name,
self.quantity
)
.fetch_one(&ctx.db)
.await?;
Ok(widget)
}
}Add the action to your router configuration.
// in router.rs or module definition
.route("/widgets", post(handle_action::<CreateWidget>))Create a dedicated test file or use the tests module in the same file.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validation() {
let action = CreateWidget { name: "Test".into(), quantity: -1 };
// Assert it returns error...
}
}