PUT
메서드: /store/{key}
key
에 해당하는 값을 저장하거나 업데이트.PUT /store/{key}/{value}
로 잘못된 RESTful 설계를 사용하고 있음.value
는 요청 본문(body)에 포함하고, key
만 URL 경로에 포함시켜야 함.#[put("/store/{key}")]
async fn put(
data: web::Data<(HashStore, Raft)>,
path: web::Path<u64>,
body: web::Json<String>
) -> impl Responder {
let key = path.into_inner();
let value = body.into_inner();
let log_entry = LogEntry::Insert { key, value };
match log_entry.encode() {
Ok(encoded_entry) => {
if let Err(e) = data.1.propose(encoded_entry).await {
return HttpResponse::InternalServerError().body(format!("Failed to propose: {}", e));
}
HttpResponse::Ok().body("OK")
}
Err(e) => HttpResponse::BadRequest().body(format!("Encoding error: {}", e)),
}
}
GET
메서드: /store/{key}
key
에 해당하는 값을 조회.GET
이 맞음.404 Not Found
반환.#[get("/store/{key}")]
async fn get(data: web::Data<(HashStore, Raft)>, path: web::Path<u64>) -> impl Responder {
let key = path.into_inner();
match data.0.get(key) {
Some(value) => HttpResponse::Ok().body(value),
None => HttpResponse::NotFound().body("Item not found"),
}
}
GET
메서드: /leader
GET
메서드 사용이 맞음.#[get("/leader")]
async fn leader(data: web::Data<(HashStore, Raft)>) -> impl Responder {
match data.1.get_leader_id().await {
Ok(leader_id) => HttpResponse::Ok().body(leader_id.to_string()),
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to get leader id: {}", e)),
}
}
POST
메서드: /leave
GET /leave
로 잘못 설계됨.POST
사용.#[post("/leave")]
async fn leave(data: web::Data<(HashStore, Raft)>) -> impl Responder {
if let Err(e) = data.1.leave().await {
return HttpResponse::InternalServerError().body(format!("Failed to leave cluster: {}", e));
}
HttpResponse::Ok().body("OK")
}
GET
메서드: /debug
GET
메서드 사용이 맞음.#[get("/debug")]
async fn debug(data: web::Data<(HashStore, Raft)>) -> impl Responder {
match data.1.inspect().await {
Ok(json) => match serde_json::from_str::<HashMap<String, Value>>(&json) {
Ok(parsed) => HttpResponse::Ok().json(parsed),
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to parse JSON: {}", e)),
}
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to inspect raft: {}", e)),
}
}
POST
메서드: /snapshot
GET /snapshot
으로 잘못 설계됨.POST
사용.#[post("/snapshot")]
async fn snapshot(data: web::Data<(HashStore, Raft)>) -> impl Responder {
match data.1.storage().await {
Ok(storage) => {
let last_index = storage.last_index().expect("Failed to get last index");
let hard_state = storage.hard_state().expect("Failed to get hard state");
match data.1.make_snapshot(last_index, hard_state.term).await {
Ok(_) => HttpResponse::Ok().body("Snapshot created successfully"),
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to make snapshot: {}", e)),
}
}
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to get storage: {}", e)),
}
}
GET
메서드: /peers
GET
메서드 사용이 맞음.#[get("/peers")]
async fn peers(data: web::Data<(HashStore, Raft)>) -> impl Responder {
match data.1.get_peers().await {
Ok(peers) => HttpResponse::Ok().json(peers),
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to get peers: {}", e)),
}
}
POST
메서드: /leave_joint
GET /leave_joint
로 잘못 설계됨.POST
사용.#[post("/leave_joint")]
async fn leave_joint(data: web::Data<(HashStore, Raft)>) -> impl Responder {
match data.1.leave_joint().await {
Ok(_) => HttpResponse::Ok().body("Node has left joint consensus"),
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to leave joint consensus: {}", e)),
}
}
POST
메서드: /transfer_leader/{id}
GET /transfer_leader/{id}
로 잘못 설계됨.POST
사용.#[post("/transfer_leader/{id}")]
async fn transfer_leader(data: web::Data<(HashStore, Raft)>, path: web::Path<u64>) -> impl Responder {
let node_id: u64 = path.into_inner();
match data.1.transfer_leader(node_id).await {
Ok(_) => HttpResponse::Ok().body("Leader transferred successfully"),
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to transfer leader: {}", e)),
}
}
POST
메서드: /campaign
GET /campaign
으로 잘못 설계됨.POST
사용.#[post("/campaign")]
async fn campaign(data: web::Data<(HashStore, Raft)>) -> impl Responder {
match data.1.campaign().await {
Ok(_) => HttpResponse::Ok().body("Campaign started successfully"),
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to start campaign: {}", e)),
}
}
POST
메서드: /demote/{term}/{leader_id}
기능: 리더 강등.
현재 상태: GET /demote/{term}/{leader_id}
로 잘못 설계됨.
적절한 수정: 리더를 강등하는 상태 변경 작업이므로 POST
사용.
#[post("/demote/{term}/{leader_id}")]
async fn demote(data: web::Data<(HashStore, Raft)>, path: web::Path<(u64, u64)>) -> impl Responder {
let (term, leader_id) = path.into_inner();
match data.1.demote(term, leader_id).await {
Ok(_) => HttpResponse::Ok().body("Leader demoted successfully"),
Err(e) => HttpResponse::InternalServerError().body(format!("Failed to demote leader: {}", e)),
}
}
GET
메서드는 읽기 전용 작업에 적합하며, 서버의 상태를 변경하지 않는 경우 사용됩니다.POST
메서드는 서버 상태를 변경하거나 리소스를 생성할 때 사용됩니다.