Basic todo example with lru cache and in-memory db
This commit is contained in:
137
src/lru_cache/handlers.rs
Normal file
137
src/lru_cache/handlers.rs
Normal file
@@ -0,0 +1,137 @@
|
||||
/// These are our API handlers, the ends of each filter chain.
|
||||
/// Notice how thanks to using `Filter::and`, we can define a function
|
||||
/// with the exact arguments we'd expect from each filter in the chain.
|
||||
/// No tuples are needed, it's auto flattened for the functions.
|
||||
use anyhow::anyhow;
|
||||
use http_api_problem::HttpApiProblem;
|
||||
use std::convert::Infallible;
|
||||
use tracing::debug;
|
||||
use warp::http::StatusCode;
|
||||
|
||||
use crate::models::{Environment, ListOptions, Todo};
|
||||
use crate::problem::reject_anyhow;
|
||||
|
||||
pub async fn list_todos(
|
||||
opts: ListOptions,
|
||||
env: Environment,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
env.caches
|
||||
.list_todos
|
||||
.get_response(opts.clone(), || async {
|
||||
// Just return a JSON array of todos, applying the limit and offset.
|
||||
let todos = env.db.lock().await;
|
||||
let todos: Vec<Todo> = todos
|
||||
.clone()
|
||||
.into_iter()
|
||||
.skip(opts.offset.unwrap_or(0))
|
||||
.take(opts.limit.unwrap_or(std::usize::MAX))
|
||||
.collect();
|
||||
Ok(warp::reply::json(&todos))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_todo(id: u64, env: Environment) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
env.caches
|
||||
.todos
|
||||
.get_response(id, || async {
|
||||
debug!("get_todo: id={}", id);
|
||||
let mut vec = env.db.lock().await;
|
||||
|
||||
// Look for the specified Todo...
|
||||
for todo in vec.iter_mut() {
|
||||
if todo.id == id {
|
||||
return Ok(warp::reply::json(&todo));
|
||||
}
|
||||
}
|
||||
|
||||
debug!(" -> todo id not found!");
|
||||
|
||||
// If the for loop didn't return OK, then the ID doesn't exist...
|
||||
Err(anyhow!(HttpApiProblem::new(format!(
|
||||
"Todo {} not found",
|
||||
id
|
||||
))
|
||||
.set_status(StatusCode::NOT_FOUND)))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_todo(create: Todo, env: Environment) -> Result<impl warp::Reply, Infallible> {
|
||||
debug!("create_todo: {:?}", create);
|
||||
|
||||
let mut vec = env.db.lock().await;
|
||||
|
||||
for todo in vec.iter() {
|
||||
if todo.id == create.id {
|
||||
debug!(" -> id already exists: {}", create.id);
|
||||
// Todo with id already exists, return `400 BadRequest`.
|
||||
return Ok(StatusCode::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
// No existing Todo with id, so insert and return `201 Created`.
|
||||
vec.push(create);
|
||||
|
||||
env.caches.list_todos.clear().await;
|
||||
Ok(StatusCode::CREATED)
|
||||
}
|
||||
|
||||
pub async fn update_todo(
|
||||
id: u64,
|
||||
update: Todo,
|
||||
env: Environment,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
debug!("update_todo: id={}, todo={:?}", id, update);
|
||||
let mut vec = env.db.lock().await;
|
||||
|
||||
// Look for the specified Todo...
|
||||
for todo in vec.iter_mut() {
|
||||
if todo.id == id {
|
||||
*todo = update;
|
||||
env.caches
|
||||
.todos
|
||||
.delete_response(id)
|
||||
.await
|
||||
.map_err(reject_anyhow)?;
|
||||
env.caches.list_todos.clear().await;
|
||||
return Ok(StatusCode::OK);
|
||||
}
|
||||
}
|
||||
|
||||
debug!(" -> todo id not found!");
|
||||
|
||||
// If the for loop didn't return OK, then the ID doesn't exist...
|
||||
Ok(StatusCode::NOT_FOUND)
|
||||
}
|
||||
|
||||
pub async fn delete_todo(id: u64, env: Environment) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
debug!("delete_todo: id={}", id);
|
||||
|
||||
let mut vec = env.db.lock().await;
|
||||
|
||||
let len = vec.len();
|
||||
vec.retain(|todo| {
|
||||
// Retain all Todos that aren't this id...
|
||||
// In other words, remove all that *are* this id...
|
||||
todo.id != id
|
||||
});
|
||||
|
||||
// If the vec is smaller, we found and deleted a Todo!
|
||||
let deleted = vec.len() != len;
|
||||
|
||||
if deleted {
|
||||
env.caches
|
||||
.todos
|
||||
.delete_response(id)
|
||||
.await
|
||||
.map_err(reject_anyhow)?;
|
||||
env.caches.list_todos.clear().await;
|
||||
// respond with a `204 No Content`, which means successful,
|
||||
// yet no body expected...
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
} else {
|
||||
debug!(" -> todo id not found!");
|
||||
Ok(StatusCode::NOT_FOUND)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user