#![deny(warnings)]
#[macro_use] extern crate log;
extern crate pretty_env_logger;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate warp;
use std::env;
use std::sync::{Arc, Mutex};
use warp::{http::StatusCode, Filter};
type Db = Arc<Mutex<Vec<Todo>>>;
#[derive(Debug, Deserialize, Serialize)]
struct Todo {
id: u64,
text: String,
completed: bool,
}
fn main() {
if env::var_os("RUST_LOG").is_none() {
env::set_var("RUST_LOG", "todos=info");
}
pretty_env_logger::init();
let db = Arc::new(Mutex::new(Vec::<Todo>::new()));
let db = warp::any().map(move || db.clone());
let todos = warp::path("todos");
let todos_index = todos.and(warp::path::index());
let todos_id = todos
.and(warp::path::param::<u64>())
.and(warp::path::index());
let json_body = warp::body::content_length_limit(1024 * 16)
.and(warp::body::json());
let list = warp::get2()
.and(todos_index)
.and(db.clone())
.map(list_todos);
let create = warp::post2()
.and(todos_index)
.and(json_body)
.and(db.clone())
.and_then(create_todo);
let update = warp::put2()
.and(todos_id)
.and(json_body)
.and(db.clone())
.and_then(update_todo);
let delete = warp::delete2()
.and(todos_id)
.and(db.clone())
.and_then(delete_todo);
let api = list
.or(create)
.or(update)
.or(delete);
let routes = api.with(warp::log("todos"));
warp::serve(routes)
.run(([127, 0, 0, 1], 3030));
}
fn list_todos(db: Db) -> impl warp::Reply {
warp::reply::json(&*db.lock().unwrap())
}
fn create_todo(create: Todo, db: Db) -> Result<impl warp::Reply, warp::Rejection> {
debug!("create_todo: {:?}", create);
let mut vec = db
.lock()
.unwrap();
for todo in vec.iter() {
if todo.id == create.id {
debug!(" -> id already exists: {}", create.id);
return Err(warp::reject::bad_request());
}
}
vec.push(create);
Ok(StatusCode::CREATED)
}
fn update_todo(id: u64, update: Todo, db: Db) -> Result<impl warp::Reply, warp::Rejection> {
debug!("update_todo: id={}, todo={:?}", id, update);
let mut vec = db
.lock()
.unwrap();
for todo in vec.iter_mut() {
if todo.id == id {
*todo = update;
return Ok(warp::reply());
}
}
debug!(" -> todo id not found!");
Err(warp::reject::not_found())
}
fn delete_todo(id: u64, db: Db) -> Result<impl warp::Reply, warp::Rejection> {
debug!("delete_todo: id={}", id);
let mut vec = db
.lock()
.unwrap();
let len = vec.len();
vec.retain(|todo| {
todo.id != id
});
let deleted = vec.len() != len;
if deleted {
Ok(StatusCode::NO_CONTENT)
} else {
debug!(" -> todo id not found!");
Err(warp::reject::not_found())
}
}