-
Notifications
You must be signed in to change notification settings - Fork 12
/
actix_crud.rs
104 lines (94 loc) · 2.64 KB
/
actix_crud.rs
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
use actix_web::{delete, get, http::StatusCode, post, web, App, HttpServer, HttpResponse, Responder};
use rustis::{
client::Client,
commands::{GenericCommands, StringCommands},
};
use std::{
fmt::{self, Display},
net::SocketAddr,
};
#[tokio::main]
async fn main() -> std::io::Result<()> {
// build rustis client in multiplexer mode (a unique rustis instance for all actix workers)
let redis = web::Data::new(Client::connect("redis://127.0.0.1:6379").await.unwrap());
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("listening on {}", addr);
HttpServer::new(move || {
App::new()
.app_data(redis.clone())
.service(read)
.service(update)
.service(delete)
})
.bind(addr)?
.run()
.await
}
#[get("/{key}")]
async fn read(
redis: web::Data<Client>,
key: web::Path<String>,
) -> Result<String, ServiceError> {
let key = key.into_inner();
let value: Option<String> = redis.get(&key).await?;
value.ok_or_else(|| {
ServiceError::new(
StatusCode::NOT_FOUND,
format!("Key `{key}` does not exist."),
)
})
}
#[post("/{key}")]
async fn update(
redis: web::Data<Client>,
key: web::Path<String>,
value: Option<String>,
) -> Result<impl Responder, ServiceError> {
let Some(value) = value else {
return Err(ServiceError::new(
StatusCode::BAD_REQUEST,
"Value not provided",
));
};
redis.set(key.into_inner(), value).await?;
Ok(HttpResponse::Ok())
}
#[delete("/{key}")]
async fn delete(
redis: web::Data<Client>,
key: web::Path<String>,
) -> Result<impl Responder, ServiceError> {
let key = key.into_inner();
let deleted = redis.del(&key).await?;
if deleted > 0 {
Ok(HttpResponse::Ok())
} else {
Err(ServiceError::new(
StatusCode::NOT_FOUND,
format!("Key `{key}` does not exist."),
))
}
}
#[derive(Debug)]
struct ServiceError(StatusCode, String);
impl ServiceError {
fn new(status_code: StatusCode, description: impl ToString) -> Self {
Self(status_code, description.to_string())
}
}
impl Display for ServiceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.1)
}
}
impl actix_web::error::ResponseError for ServiceError {
fn status_code(&self) -> actix_web::http::StatusCode {
self.0
}
}
impl From<rustis::Error> for ServiceError {
fn from(e: rustis::Error) -> Self {
eprintln!("rustis error: {e}");
ServiceError::new(StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error")
}
}