From f3ccc4f1949df6cf19576a6ff91eeccbabd807b4 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 5 Jul 2024 22:56:25 -0700 Subject: [PATCH] Update backend to allow creating tasks to work with the browser. --- migrations/0001_create_tasks.sql | 6 ++++++ src/global.rs | 9 ++++++++- src/main.rs | 4 +++- src/routes/tasks.rs | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 migrations/0001_create_tasks.sql diff --git a/migrations/0001_create_tasks.sql b/migrations/0001_create_tasks.sql new file mode 100644 index 0000000..7bbd730 --- /dev/null +++ b/migrations/0001_create_tasks.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS task ( + id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + title text NOT NULL, + description text, + CHECK(title <> '') +); diff --git a/src/global.rs b/src/global.rs index c6ee835..fb49661 100644 --- a/src/global.rs +++ b/src/global.rs @@ -1,8 +1,15 @@ -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; +use serde::Serialize; use sqlx::SqlitePool; #[derive(Clone)] pub struct AppState { pub db_pool: Arc, } + +#[derive(Serialize)] +pub struct FormErrorResponse { + pub message: String, + pub field_errors: HashMap, +} diff --git a/src/main.rs b/src/main.rs index 0c236e7..7f6dfc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,9 @@ async fn main() { .fallback(handle404) .route( "/tasks", - get(routes::tasks::list).post(routes::tasks::create), + get(routes::tasks::list) + .post(routes::tasks::create) + .options(routes::tasks::options), ) .with_state(state); diff --git a/src/routes/tasks.rs b/src/routes/tasks.rs index 397abaf..78124a8 100644 --- a/src/routes/tasks.rs +++ b/src/routes/tasks.rs @@ -1,9 +1,12 @@ +use std::collections::HashMap; + use axum::extract::{Json, State}; use axum::http::header; use axum::http::StatusCode; use axum::response::IntoResponse; use serde::Deserialize; +use crate::global::FormErrorResponse; use crate::{global::AppState, models::Task}; pub async fn list(state: State) -> impl IntoResponse { @@ -23,6 +26,23 @@ pub struct NewTask { } pub async fn create(state: State, Json(req): Json) -> impl IntoResponse { + if req.title.is_empty() { + return ( + StatusCode::BAD_REQUEST, + [(header::ACCESS_CONTROL_ALLOW_ORIGIN, "*")], + serde_json::to_string(&FormErrorResponse { + message: "Failed to validate new task".to_string(), + field_errors: [( + "title".to_string(), + "Task title must not be empty.".to_string(), + )] + .iter() + .cloned() + .collect(), + }) + .unwrap(), + ); + } let task = Task::new(req.title, req.description); let new_task = task.insert(&state.db_pool).await.unwrap(); @@ -33,3 +53,15 @@ pub async fn create(state: State, Json(req): Json) -> impl In serde_json::to_string(&new_task).unwrap(), ) } + +pub async fn options() -> impl IntoResponse { + ( + StatusCode::OK, + [ + (header::ACCESS_CONTROL_ALLOW_ORIGIN, "*"), + (header::ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, OPTIONS"), + (header::ACCESS_CONTROL_ALLOW_HEADERS, "Content-Type"), + (header::ACCESS_CONTROL_MAX_AGE, "86400"), + ], + ) +}