use actix_web::{guard, web, App, Either, Error, HttpRequest, HttpResponse, HttpServer, Responder}; use futures::future::{ready, Ready}; use listenfd::ListenFd; use serde::{Deserialize, Serialize}; #[derive(Serialize)] struct Product { id: u32, name: String, quantity: i32, cents: u32, img_path: String, description: String, } impl Responder for Product { type Error = Error; type Future = Ready>; fn respond_to(self, _req: &HttpRequest) -> Self::Future { let body = serde_json::to_string(&self).unwrap(); ready(Ok(HttpResponse::Ok() .content_type("application/json") .body(body))) } } #[derive(Deserialize)] struct NewProduct { name: String, quantity: i32, cents: u32, img_path: String, description: String, } type ProductResult = Either>; async fn get_single_product(path: web::Path<(u32,)>) -> ProductResult { let id = path.0; if id != 1 { Either::A(HttpResponse::BadRequest().body("bad data")) } else { Either::B(Ok(Product { id: 1, name: "Beach Box".to_string(), quantity: 3, cents: 1100, img_path: "/beach_box.jpg".to_string(), description: "It's a beach in a box".to_string(), })) } } async fn get_all_products() -> impl Responder { let product = Product { id: 1, name: "Beach Box".to_string(), quantity: 3, cents: 1100, img_path: "/beach_box.jpg".to_string(), description: "It's a beach in a box".to_string(), }; web::Json(vec![product]) } async fn create_product(new_product: web::Json) -> impl Responder { Product { id: 2, name: new_product.name.to_owned(), quantity: new_product.quantity, cents: new_product.cents, img_path: new_product.img_path.to_owned(), description: new_product.description.to_owned(), } } async fn index() -> impl Responder { "Hello, this is an API. If you're looking for the web app, try the top-level domain at port 443.".to_string() } #[actix_rt::main] async fn main() -> std::io::Result<()> { let mut listenfd = ListenFd::from_env(); let mut server = HttpServer::new(|| { App::new() .route("/", web::get().to(index)) .service( web::resource("/products") .route( web::route() .guard(guard::Get()) .guard(guard::Header("content-type", "application/json")) .to(get_all_products), ) .route( web::route() .guard(guard::Post()) .guard(guard::Header("content-type", "application/json")) .to(create_product), ), ) .service( web::resource("/products/{id}").route( web::route() .guard(guard::Get()) .guard(guard::Header("content-type", "application/json")) .to(get_single_product), ), ) }); server = if let Some(l) = listenfd.take_tcp_listener(0).unwrap() { server.listen(l)? } else { server.bind("127.0.0.1:8000")? }; server.run().await }