NotFound error and add validation

This commit is contained in:
Tyler Hallada 2023-05-07 19:50:44 -04:00
parent de157a3b1e
commit f30be5f451
3 changed files with 26 additions and 8 deletions

View File

@ -1,8 +1,8 @@
CREATE TABLE IF NOT EXISTS "items" ( CREATE TABLE IF NOT EXISTS "items" (
"id" SERIAL PRIMARY KEY NOT NULL, "id" SERIAL PRIMARY KEY NOT NULL,
"title" VARCHAR(255) NOT NULL, "title" VARCHAR(255) NOT NULL,
"url" VARCHAR(255) NOT NULL, "url" VARCHAR(2048) NOT NULL,
"description" VARCHAR(255), "description" TEXT,
"created_at" timestamp(3) NOT NULL, "created_at" timestamp(3) NOT NULL,
"updated_at" timestamp(3) NOT NULL, "updated_at" timestamp(3) NOT NULL,
"deleted_at" timestamp(3) "deleted_at" timestamp(3)

View File

@ -21,8 +21,13 @@ pub enum Error {
#[error("validation error in request body")] #[error("validation error in request body")]
InvalidEntity(#[from] ValidationErrors), InvalidEntity(#[from] ValidationErrors),
#[error("{0} not found")]
NotFound(&'static str),
} }
pub type Result<T, E = Error> = ::std::result::Result<T, E>;
impl IntoResponse for Error { impl IntoResponse for Error {
fn into_response(self) -> Response { fn into_response(self) -> Response {
#[serde_with::serde_as] #[serde_with::serde_as]
@ -59,7 +64,7 @@ impl Error {
use Error::*; use Error::*;
match self { match self {
Sqlx(sqlx::Error::RowNotFound) => StatusCode::NOT_FOUND, NotFound(_) => StatusCode::NOT_FOUND,
Sqlx(_) | Anyhow(_) => StatusCode::INTERNAL_SERVER_ERROR, Sqlx(_) | Anyhow(_) => StatusCode::INTERNAL_SERVER_ERROR,
InvalidEntity(_) => StatusCode::UNPROCESSABLE_ENTITY, InvalidEntity(_) => StatusCode::UNPROCESSABLE_ENTITY,
} }

View File

@ -1,6 +1,9 @@
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::PgPool; use sqlx::PgPool;
use validator::Validate;
use crate::error::{Error, Result};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Item { pub struct Item {
@ -13,17 +16,26 @@ pub struct Item {
deleted_at: Option<NaiveDateTime>, deleted_at: Option<NaiveDateTime>,
} }
#[derive(Deserialize)] #[derive(Debug, Deserialize, Validate)]
pub struct CreateItem { pub struct CreateItem {
#[validate(length(max = 255))]
title: String, title: String,
#[validate(url)]
url: String, url: String,
#[validate(length(max = 524288))]
description: Option<String>, description: Option<String>,
} }
pub async fn get_item(pool: PgPool, id: i32) -> sqlx::Result<Item> { pub async fn get_item(pool: PgPool, id: i32) -> Result<Item> {
sqlx::query_as!(Item, "SELECT * FROM items WHERE id = $1", id) sqlx::query_as!(Item, "SELECT * FROM items WHERE id = $1", id)
.fetch_one(&pool) .fetch_one(&pool)
.await .await
.map_err(|error| {
if let sqlx::error::Error::RowNotFound = error {
return Error::NotFound("item");
}
Error::Sqlx(error)
})
} }
pub async fn get_items(pool: PgPool) -> sqlx::Result<Vec<Item>> { pub async fn get_items(pool: PgPool) -> sqlx::Result<Vec<Item>> {
@ -32,8 +44,9 @@ pub async fn get_items(pool: PgPool) -> sqlx::Result<Vec<Item>> {
.await .await
} }
pub async fn create_item(pool: PgPool, payload: CreateItem) -> sqlx::Result<Item> { pub async fn create_item(pool: PgPool, payload: CreateItem) -> Result<Item> {
sqlx::query_as!( payload.validate()?;
Ok(sqlx::query_as!(
Item, Item,
"INSERT INTO items ( "INSERT INTO items (
title, url, description, created_at, updated_at title, url, description, created_at, updated_at
@ -45,5 +58,5 @@ pub async fn create_item(pool: PgPool, payload: CreateItem) -> sqlx::Result<Item
payload.description payload.description
) )
.fetch_one(&pool) .fetch_one(&pool)
.await .await?)
} }