Update backend to allow creating tasks to work with the browser.
This commit is contained in:
parent
d2dfbb9a4a
commit
f3ccc4f194
|
@ -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 <> '')
|
||||||
|
);
|
|
@ -1,8 +1,15 @@
|
||||||
use std::sync::Arc;
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
|
use serde::Serialize;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub db_pool: Arc<SqlitePool>,
|
pub db_pool: Arc<SqlitePool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct FormErrorResponse {
|
||||||
|
pub message: String,
|
||||||
|
pub field_errors: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,9 @@ async fn main() {
|
||||||
.fallback(handle404)
|
.fallback(handle404)
|
||||||
.route(
|
.route(
|
||||||
"/tasks",
|
"/tasks",
|
||||||
get(routes::tasks::list).post(routes::tasks::create),
|
get(routes::tasks::list)
|
||||||
|
.post(routes::tasks::create)
|
||||||
|
.options(routes::tasks::options),
|
||||||
)
|
)
|
||||||
.with_state(state);
|
.with_state(state);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use axum::extract::{Json, State};
|
use axum::extract::{Json, State};
|
||||||
use axum::http::header;
|
use axum::http::header;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::global::FormErrorResponse;
|
||||||
use crate::{global::AppState, models::Task};
|
use crate::{global::AppState, models::Task};
|
||||||
|
|
||||||
pub async fn list(state: State<AppState>) -> impl IntoResponse {
|
pub async fn list(state: State<AppState>) -> impl IntoResponse {
|
||||||
|
@ -23,6 +26,23 @@ pub struct NewTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create(state: State<AppState>, Json(req): Json<NewTask>) -> impl IntoResponse {
|
pub async fn create(state: State<AppState>, Json(req): Json<NewTask>) -> 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 task = Task::new(req.title, req.description);
|
||||||
|
|
||||||
let new_task = task.insert(&state.db_pool).await.unwrap();
|
let new_task = task.insert(&state.db_pool).await.unwrap();
|
||||||
|
@ -33,3 +53,15 @@ pub async fn create(state: State<AppState>, Json(req): Json<NewTask>) -> impl In
|
||||||
serde_json::to_string(&new_task).unwrap(),
|
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"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue