REST API 녹 슬림 + 휨 2: POST
POST
을 구축합니다.곡속교전!
The code for this part is available .
POST
은 일부 데이터를 삽입하기 위해 서버에 요청을 보냅니다.이 데이터는 JSON 형식으로 전송됩니다.그리고 이 프로그램의 작업은 JSON을 해석하고 저장하는 것이다. (메모리에만 있다. 나는 이 시리즈에서 ORM을 토론하지 않을 것이다. 아마도 다른 시리즈에 있을 것이다.)홀로그램 갑판 생성 시뮬레이션 (만약 당신이 스타크래프트를 좋아하지 않는다면 이 말을 무시하십시오.)이 점을 감안하여 나는 KISS원칙을 따르고 이를'simulation id'와'simulation name'의 키 값으로 설정했다.
우선, 내가 무엇을 열거해야 하는지 알았을 때, 나는 이전의
list()
을 list_sims()
, handle_list()
을 handle_list_sims()
으로 바꾸었다.그리고 저는
try_create()
테스트 함수를 만들었습니다. 이전의 테스트와 매우 비슷합니다. 이것은 새로운 필터를 사용하여 방법(이번은 POST
)을 같은 /holodeck
경로로 보내고 좋은 답을 기대합니다(what could go wrong in the holodeck?).// Add "models" in the already existing line "use super::filters;":
use super::{filters,models};
#[tokio::test]
async fn try_create() {
let db = models::new_db();
let api = filters::post_sim(db);
let response = request()
.method("POST")
.path("/holodeck")
.json(&models::Simulation{
id: 1,
name: String::from("The Big Goodbye")
})
.reply(&api)
.await;
assert_eq!(response.status(), StatusCode::CREATED);
}
발생할 수 있는 문제(기타 제외)는 중복 항목으로 인한 충돌이다.그래서 나도 이 때문에 테스트를 했다.#[tokio::test]
async fn try_create_duplicates() {
let db = models::new_db();
let api = filters::post_sim(db);
let response = request()
.method("POST")
.path("/holodeck")
.json(&models::Simulation{
id: 1,
name: String::from("Bride Of Chaotica!")
})
.reply(&api)
.await;
assert_eq!(response.status(), StatusCode::CREATED);
let response = request()
.method("POST")
.path("/holodeck")
.json(&models::Simulation{
id: 1,
name: String::from("Bride Of Chaotica!")
})
.reply(&api)
.await;
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}
JSON이 전달하는 Simulation
의 구조는 아직 정의가 필요하다. (이것은 테스트 모듈의 use super::models
이 use
문장을 주의해야 한다. 나는 어떤 문장도 언급하는 것을 잊지 않기를 바란다.)post_sim()
을 작성하기 전에 세 가지가 필요합니다. [1] 처리와 지구화 데이터의 유형(메모리에만 있음), [2] JSON 본문 하나, 그리고 [3] 데이터를 포장하는 방법입니다.[1]부터: 나는 먼저
serde
판자 상자로 서열화를 처리해야 하기 때문에 [dependencies]
의 Cargo.toml
아래에 이 줄을 추가했다.serde = { version = "1", features = ["derive"]}
이 문제를 해결한 후에 저는 다시 lib.rs
으로 돌아가서 mod
을 만들었습니다. 이것은 type
과 struct
이 있습니다. serde 매크로 때문에 자동으로 JSON 형식의 데이터를 서열화할 수 있습니다.아, 그리고 없는 곳이 없는 new()
함수(이것은 수첩에서 일반적으로 알려주는 실현 중의 함수가 아니다. 왜냐하면 나는 type
에서 Db
을 사용했기 때문이다. 왜냐하면 나는 그것을 struct
에 끼워 넣고 싶지 않기 때문이다).mod models {
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::sync::Arc;
use tokio::sync::Mutex;
#[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]
pub struct Simulation {
pub id: u64,
pub name: String,
}
pub type Db = Arc<Mutex<HashSet<Simulation>>>;
pub fn new_db() -> Db {
Arc::new(Mutex::new(HashSet::new()))
}
}
지금 나는 왜 이런 스마트 포인터를 선택했을까?Arc
에 좋은 대체 방안이 없다고 생각한다. 왜냐하면 나는 해시집의 라인에 대한 안전한 인용이 필요하기 때문이다.Mutex
에 관해서, 나는 본래 RwLock
으로 대체하여, 동시에 읽을 수 있도록 할 수 있었지만, 상하문을 고려하면, 이것은 필요없을 것 같다.[2]: JSON body 함수는 앞에서 언급한 쿨한 아이의 예에서 복제한 것으로
filters
mod에 놓여 있다.그것은 크지 않으면 어떤 JSON체도 받아들인다.// This line already exists; I just added "models"
use super::{handlers, models};
fn json_body() -> impl Filter<Extract = (models::Simulation,), Error = warp::Rejection> + Clone {
warp::body::content_length_limit(1024 * 16).and(warp::body::json())
}
그것을 묶기 위해서[3], 우리는 filters
의 또 다른 새로운 함수가 필요하다.이 함수 post_sim()
은 JSON 주체와 Db(우리 Archandle_create_sim()
에 보냅니다.pub fn post_sim(db: models::Db) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
let db_map = warp::any()
.map(move || db.clone());
warp::path!("holodeck")
.and(warp::post())
.and(json_body())
.and(db_map)
.and_then(handlers::handle_create_sim)
}
여기서 더 이해하기 어려울 것 같은 것은 let db_map
이다.warp::any
은 catch all이다.즉, 그것은 아무것도 거르지 않는 필터이다.그래서 우리가 여기서 하는 일은 우리의 데이터베이스가 필터에 포장되어 있는지 확인하는 것이다. 그러면 우리는 그것을 네가 본 .and(db_map)
에 붙일 수 있다.and 트리거된
handle_create_sim()
에서 handlers
모듈 내부로 들어가면 다음과 같다.// Add this "use" below the others
use super::models;
pub async fn handle_create_sim(sim: models::Simulation, db: models::Db) -> Result<impl warp::Reply, Infallible> {
let mut map = db.lock().await;
if let Some(result) = map.get(&sim){
return Ok(warp::reply::with_status(
format!("Simulation #{} already exists under the name {}", result.id, result.name),
StatusCode::BAD_REQUEST,
));
}
map.insert(sim.clone());
Ok(warp::reply::with_status(format!("Simulation #{} created", sim.id), StatusCode::CREATED))
}
이것은 JSON(Simulation)과 HashSet(db:db)을 받아들인다. 항목이 이미 존재하면 오류를 되돌려주거나 JSON 데이터를 HashSet에 삽입하거나 그렇지 않으면 success를 되돌려줍니다.Here having a HashMap would clearly be the better solution, as it would allow us to compare keys. We'll solve this in part 2.
나는 본래
Ok(StatusCode::CREATED)
과 Ok(StatusCode::BAD_REQUEST)
으로 warp::reply::with_status
을 대체할 수 있었지만, 나는 잘못을 처리할 생각이 없기 때문에, 나는 이것이 적어도 내가 할 수 있는 일이라고 생각한다.$ cargo test
running 3 tests
test tests::try_create ... ok
test tests::try_create_duplicates ... ok
test tests::try_list ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
그래, 그래, 그래.다음 회'왜곡과의 교전'에서...
다음은
GET
방법입니다. 이것은 매개 변수 처리와 (최종) 처리 이 해시 집합을 볼 수 있음을 의미합니다.🖖
Reference
이 문제에 관하여(REST API 녹 슬림 + 휨 2: POST), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/rogertorres/rest-api-with-rust-warp-2-post-3527텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)