REST API 및 Rust+Warp 3:

24739 단어 rustrestwarpapi
어서 오세요!지난번에 우리가 만났을 때 나는 다음과 같이 썼다.

Next in line is the GET method, which means we'll see parameter handling and (finally) deal with this HashSet thing.


그래서 "심심한 토론에 시간을 낭비하지 말자!"

곡속 3, 이렇게!

The code for this part is available .


우선, 나는 반서열화 GET 를 되돌릴 수 있도록 다른 의존항이 필요하다. 그래서 나는 Cargo.toml 파일을 변경했다.
serde_json = "1.0"
그리고 바꿀 때가 됐어요try_list().우리가 지난번에 만났을 때 이 테스트는 하나request()와 하나assert_eq!뿐이었다.나는 두 가지를 보충했다.
  • 요청을 하기 전에 나는 하히에 두 항목을 수동으로 삽입했다POST. (나는 호출할 수 있었는데db.lock().await.insert() 다른 곳에서 테스트를 했기 때문에 이 단축키를 사용할 수 있다).
  • 요청 후에 HTML 본문을 반서열화하고 그 내용을 내가 이전에 삽입한 데이터와 비교했다.
  • 이상하게 보일 수도 있지만 걱정하지 마세요. 제가 하나씩 소개할게요.
    use std::collections::HashSet;
    
    #[tokio::test]
    async fn try_list() {
        use std::str;
        use serde_json;
    
        let simulation1 = models::Simulation{
            id: 1, 
            name: String::from("The Big Goodbye"),
        };
    
    
        let simulation2 = models::Simulation{
            id: 2, 
            name: String::from("Bride Of Chaotica!"),
        };
    
        let db = models::new_db();
        db.lock().await.insert(simulation1.clone());
        db.lock().await.insert(simulation2.clone());
    
        let api = filters::list_sims(db);
    
        let response = request()
            .method("GET")
            .path("/holodeck")
            .reply(&api)
            .await;
    
        let result: Vec<u8> = response.into_body().into_iter().collect();
        let result = str::from_utf8(&result).unwrap();
        let result: HashSet<models::Simulation> = serde_json::from_str(result).unwrap();
        assert_eq!(models::get_simulation(&result, 1).unwrap(), &simulation1);
        assert_eq!(models::get_simulation(&result, 2).unwrap(), &simulation2);
    
        let response = request()
            .method("GET")
            .path("/holodeck/2")
            .reply(&api)
            .await;
    
        let result: Vec<u8> = response.into_body().into_iter().collect();
        let result = str::from_utf8(&result).unwrap();
        let result: HashSet<models::Simulation> = serde_json::from_str(result).unwrap();
        assert_eq!(result.len(),1);
        assert_eq!(models::get_simulation(&result, 2).unwrap(), &simulation2);
    }
    
    내가 설명할 만한 첫 번째 일은 lock()이다.std::sync::Mutex는 호 안의 내용을 제시했는데 이 예에서 하나를 되돌려준다Future.왜?우리가 사용하는 것은 tokio::sync::Mutex이 아니라 unwrap()이기 때문에 전자의 비동기적인 실현이다.이것이 바로 우리가 await가 아니라 filters::list_sims()인 이유이다suspend execution until the result of the Future is ready.
    그런 다음 serde_json::from_str() 이제 HTTP 바디에서 데이터를 반환하는 매개변수가 생성됩니다.
    요청이 변하지 않은 후에 세 줄 바이트로 jibber jabber를 처리합니다.
    Bytes는 WarpRequestBuilder가 HTML 본문 내용을 처리하는 형식입니다.그것은 마치 [u8](즉 원시 u8의 수조)처럼 보이지만, 처리하기에는 좀 고통스럽다. 그러나 나는 그것으로 하는 일은 매우 간단하다.
  • 그 내용을 u8
  • 의 벡터에 비추다
  • 벡터의 내용을 슬라이스로 이동
  • 함수를 사용하여 해시가 집중된 Simulation struct에 비추다.
  • 이것이 바로 내가 해시집을 원하는 이유 중의 하나다.standard Rust에서는 두 필드의 구조를 참조하는 HashMap을 만들 수 없는 것으로 알고 있습니다.즉, 너는 이렇게 해서는 안 된다.
    \\ This code is not in the project!
    struct Example {
        id: u64,
        name: String,
    }
    
    type Impossible = HashMap<Example>;
    
    내가 해시맵처럼 struct(쿨한 아이들이 205행에서 Vectorhere를 사용하는 것처럼)를 사용하지 않고 serde를 사용하면 얻을 수 있다.복잡하다.
    그럼에도 불구하고 해시집중에 구조를 붙이고 싶은 또 다른 이유는 내 유형에 특성을 실현할 수 있는 기회를 주기 때문이다.
    이러한 특징을 깊이 있게 연구하기 전에 나는 테스트의 마지막 부분을 설명하고 싶다(이것은 다른 테스트일 것이다. 그러나 이 예는 이미 너무 크다).GET 방법은 세 가지 다른 사용 방식이 있다.
  • 모든 항목 가져오기: /holodeck
  • 단일 항목 가져오기: /holodeck/:id
  • 필터 항목 가져오기: /holodeck/?search=query
  • 마지막 request() 사용 경로/holodeck/2는 두 번째 사례를 덮어쓰기 위해 작성된 것이다.나는 세 번째를 개발하지 못했다.

    대담하게 특성을 실현하다
    HashSet 요소를 다른 요소와 비교하면 모든 컨텐트가 비교됩니다.만약 네가 키 값이 구조에 맞다면 좋지 않을 것이다.상기 이유로 저는 HashMap을 사용하고 싶지 않기 때문에 이런 행동을 바꾸고 id만 비교하는 것을 해야 합니다.
    우선, 나는 HashHasher를 가져왔고, 그리고 나는 Eq, PartialEqHash를 삭제했다. 그러면 나는 스스로 그것을 실현할 수 있다.구현 프로세스는 다음과 같습니다.
    use std::hash::{Hash, Hasher};
    
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Simulation {
        pub id: u64,
        pub name: String,
    }
    
    impl PartialEq for Simulation{
        fn eq(&self, other: &Self) -> bool {
            self.id == other.id
        }
    }
    
    impl Eq for Simulation {}
    
    impl Hash for Simulation{
        fn hash<H: Hasher>(&self, state: &mut H){
                self.id.hash(state);
        }
    }
    
    어떻게 하는지 내가 어떻게 알아?나는 단지 서류에 적힌 대로 "How can I implement Eq?" 했을 뿐이다.네, 녹슨 의사는 아주 좋아요.
    그럼 잡채는요?같은 일.근데 재밌는 건 내가 왜 이러는지.해시 집합 수요Hash 특성, 해시 특성 요구:
    k1 == k2 -> hash(k1) == hash(k2)
    
    이것은 비교의 값이 같으면 그들의 하쉬 값도 반드시 같아야 한다는 것을 의미한다. 이것은 PartialEqEq가 실현된 후에 성립되지 않는다. 왜냐하면 이 두 값이 모두 하쉬와 비교되고 직접적인 비교는 관심만 있기 때문이다id.

    99% chance that I am wrong, but I think it should not be an implication (→), but a biconditional (↔), because the way it stands if k1 == k2 is false and hash(k1) == hash(k2) is true, the implication's result is still true. But I am not a trained computer scientist and I am not sure this uses first-order logic notation. Let me know in the comments if you do.


    내가 산열 실현 아래에서 한 마지막 보충은 다음과 같다.
    pub fn get_simulation<'a>(sims: &'a HashSet<Simulation>, id: u64) -> Option<&'a Simulation>{
        sims.get(&Simulation{
            id,
            name: String::new(),
        })
    }
    
    비록 id 등의 방법을 사용할 때 비교에 사용되는 유일한 관련 필드는 get()이지만 우리는 전체 구조를 전달해야 하기 때문에 나는 get_simulation()를 만들어서 그것을 대체했다.
    네, 돌아오는 방법GET입니다.

    법외에서 소요하다.
    처리 GET 방법의 함수는 현재 결과를 얻을 수 있는 해시 집합과 사용할 수 있는 인자 두 개의 추가 정보를 처리해야 한다.
    pub fn list_sims(db: models::Db) ->  impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
        let db_map = warp::any()
            .map(move || db.clone());
    
        let opt = warp::path::param::<u64>()
            .map(Some)
            .or_else(|_| async { 
                // Ok(None) 
                Ok::<(Option<u64>,), std::convert::Infallible>((None,))
            });
    
        warp::path!("holodeck" / ..)
            .and(opt)
            .and(warp::path::end())
            .and(db_map)
            .and_then(handlers::handle_list_sims)
    }
    
    opt는 보낼 수 있는 선택할 수 있는 매개 변수를 나타낸다.그것은 매개 변수를 얻어 Option (즉 Some 로 비추었다.제공되지 않은 경우 or_else() 반환Noneasync가 있는 이유는 or_else()returns a TryFuture 때문이다.
    우리가 실제로 되돌아온 path는 이것opt을 포함하고 우리db_bap를 포함하는 방식과 같다./ ..path!는 매크로에 추가하지 말라고 end()했다. 그러면 내가 추가할 수 있다opt.이것이 바로 머지않아 수첩end()이 나올 수 있는 이유다.

    I didn't found this solution in the docs or in the examples. Actually, for some reason, most tutorials omit GET parameters. They either just list everything or use query. I found one tutorial that implemented this, but they did so by creating two filters and two handlers. It didn't felt ok, and I knew there should be a solution and that the problem was probably my searching skills; so I asked for help in warp's discord channel, and the nice gentleman jxs pointed me to the solution you saw above.


    다음 단계는 복구 프로세서입니다.
    pub async fn handle_list_sims(param: u64, db: models::Db) -> Result<impl warp::Reply, Infallible> {
        let mut result = db.lock().await.clone();
        if param > 0 {
            result.retain(|k| k.id == param);
        };
        Ok(warp::reply::json(&result)) 
    }
    
    그것은 더 이상 매튜 맥콘나 한들러 (Matthew McConaughey handler) 가 아니지만, 여전히 매우 간단하다.나는 retain 대신 get_simulation() 을 사용합니다. 왜냐하면 이것은 HashSet을 되돌려주기 때문입니다. (get은 나에게 models::Simulation 이것은 바로 처리 프로그램이 되돌려야 하는 것입니다.
    $ 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
    

    다음 회'왜곡과의 교전'에서...
    우리는 실현PUTDELETE 방법을 통해 실현할 것이다.
    🖖

    좋은 웹페이지 즐겨찾기