1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
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<Result<HttpResponse, Error>>;
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<HttpResponse, Result<Product, Error>>;
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<NewProduct>) -> 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
}
|