-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathaxum_crud.rs
94 lines (84 loc) · 2.38 KB
/
axum_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
use axum::{
extract::{Path, State},
http::StatusCode,
response::{IntoResponse, Response},
routing::get,
Router,
};
use rustis::{
client::Client,
commands::{GenericCommands, StringCommands},
};
use std::{net::SocketAddr, sync::Arc};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
// build rustis client in multiplexer mode (a unique rustis instance for all axum workers)
let redis = Arc::new(Client::connect("redis://127.0.0.1:6379").await.unwrap());
// build our application with a route
let app = Router::new()
.route("/:key", get(read).post(update).delete(del))
.with_state(redis);
// run it
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("listening on {}", addr);
let listener = TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn read(
State(redis): State<Arc<Client>>,
Path(key): Path<String>,
) -> Result<String, ServiceError> {
let value: Option<String> = redis.get(&key).await?;
value.ok_or_else(|| {
ServiceError::new(
StatusCode::NOT_FOUND,
format!("Key `{key}` does not exist."),
)
})
}
async fn update(
State(redis): State<Arc<Client>>,
Path(key): Path<String>,
value: String,
) -> Result<(), ServiceError> {
if value.is_empty() {
return Err(ServiceError::new(
StatusCode::BAD_REQUEST,
"Value not provided",
));
}
redis.set(key, value).await?;
Ok(())
}
async fn del(
State(redis): State<Arc<Client>>,
Path(key): Path<String>,
) -> Result<(), ServiceError> {
let deleted = redis.del(&key).await?;
if deleted > 0 {
Ok(())
} else {
Err(ServiceError::new(
StatusCode::NOT_FOUND,
format!("Key `{key}` does not exist."),
))
}
}
struct ServiceError(StatusCode, String);
impl ServiceError {
fn new(status_code: StatusCode, description: impl ToString) -> Self {
Self(status_code, description.to_string())
}
}
impl IntoResponse for ServiceError {
fn into_response(self) -> Response {
(self.0, self.1).into_response()
}
}
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")
}
}