REST API with Rust + Warp 4: PUT & DELETE

That’s it, the last methods. In the beginning, I thought it would be the end of the series, but then I realized it needed an additional post, regarding how to manually test it using curl. However, before that, there are still two more methods to be cod…


This content originally appeared on DEV Community and was authored by Roger Torres

That's it, the last methods. In the beginning, I thought it would be the end of the series, but then I realized it needed an additional post, regarding how to manually test it using curl. However, before that, there are still two more methods to be coded. But don't worry, both combined are probably easier than the single ones we handled so far.

Warp 4, Mr. Sulu.

The code for this part is available here.

The PUT method is a mix between insert and change: it creates an entry when the data is not there and updates it when it is.

This behavior is already met by our HashSet; this is exactly how the insert() function works. However, we got to know if we are inserting or changing because the status that is returned got to be different:

  • Code 201 when it is created
  • Code 200 when it is updated

Where did I get this from? It is written here.

With that in mind, I wrote this code:

#[tokio::test]
async fn try_update() {
    let db = models::new_db();
    let api = filters::update_sim(db);

    let response = request()
        .method("PUT")
        .path("/holodeck/1")
        .json(&models::Name{ new_name: String::from("The Big Goodbye")})
        .reply(&api)
        .await;

    assert_eq!(response.status(), StatusCode::CREATED);

    let response = request()
        .method("PUT")
        .path("/holodeck/1")
        .json(&models::Name{ new_name: String::from("The Short Hello")})
        .reply(&api)
        .await;

    assert_eq!(response.status(), StatusCode::OK);
}

How did I knew that 201 was StatusCode::CREATED and 200 was StatusCode::OK? Here.

As you can see, the request is made by sending the parameter id ("1", in this case). Different from GET, this parameter is mandatory. And because the id is already being sent in the URI, the body only contains the name. The reasoning behind this is also in the aforementioned rfc.

Because of this, I implemented a new struct and a new function to get the JSON body.

#[derive(Debug, Deserialize, Serialize)]
pub struct NewName{ pub name: String }
// This code is inside the mod "filters"
fn json_body_put() -> impl Filter<Extract = (models::NewName,), Error = warp::Rejection> + Clone {
    warp::body::content_length_limit(1024 * 16).and(warp::body::json())
}

This is certainly a suboptimal way of doing this. But let's move on anyway; I am saving the excuses about the poor execution of things to the last part.

Now, the filter and the handler.

// This is inside the mod "filters"
pub fn update_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" / u64)
        .and(warp::put())
        .and(json_body_put())
        .and(db_map)
        .and_then(handlers::handle_update_sim)
}
pub async fn handle_update_sim(id: u64, new: models::NewName, db: models::Db) -> Result<impl warp::Reply, Infallible> {
    // Replaced entry
    if let Some(_) = db.lock().await.replace(Simulation{id, name: new.name}){
        return Ok(warp::reply::with_status(
            format!("Simulation #{} was updated.\n", id), 
            StatusCode::OK,
        ));
    }

    // Create entry
    Ok(warp::reply::with_status(
        format!("Simulation #{} was inserted.\n", id), 
        StatusCode::CREATED,
    ))
}

And that's it!

Red alert

To warp wrap things up, the DELETE method.

As usual, the request is quite simple: it sends the id as a parameter and no body. As a response, we expect code 200 (OK) including a "representation describing the status".

#[tokio::test]
async fn try_delete() {
    let simulation = models::Simulation{
        id: 1, 
        name: String::from("The Big Goodbye!"),
    };

    let db = models::new_db();
    db.lock().await.insert(simulation);

    let api = filters::delete_sim(db);

    let response = request()
        .method("DELETE")
        .path("/holodeck/1")
        .reply(&api)
        .await;

        assert_eq!(response.status(), StatusCode::OK);
}

Hopefully, nothing about the filter implementation seems strange to you:

pub fn delete(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" / u64)
        .and(warp::delete())
        .and(db_map)
        .and_then(handlers::handle_delete_sim)
}

Since it is the first time we're deleting data, the handler has a unique behavior, but also nothing very different from what has been done so far.

pub async fn handle_delete_sim(id: u64, db: models::Db) -> Result<impl warp::Reply, Infallible> {
    if db.lock().await.remove(&Simulation{id, name: String::new(),}){
        return Ok(warp::reply::with_status(
            format!("Simulation #{} was deleted", id), 
            StatusCode::OK,
        ))
    };

    Ok(warp::reply::with_status(
        format!("No data was deleted."),
        StatusCode::OK,
    ))
}

That should do...

$ cargo test

running 5 tests
test tests::try_delete ... ok
test tests::try_create ... ok
test tests::try_list ... ok
test tests::try_create_duplicates ... ok
test tests::try_update ... ok

test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

And it did!

In the next episode of Engaging Warp...

Finally, the last part. We will serve what has been built and curl against it.

?


This content originally appeared on DEV Community and was authored by Roger Torres


Print Share Comment Cite Upload Translate Updates
APA

Roger Torres | Sciencx (2021-04-14T12:21:26+00:00) REST API with Rust + Warp 4: PUT & DELETE. Retrieved from https://www.scien.cx/2021/04/14/rest-api-with-rust-warp-4-put-delete/

MLA
" » REST API with Rust + Warp 4: PUT & DELETE." Roger Torres | Sciencx - Wednesday April 14, 2021, https://www.scien.cx/2021/04/14/rest-api-with-rust-warp-4-put-delete/
HARVARD
Roger Torres | Sciencx Wednesday April 14, 2021 » REST API with Rust + Warp 4: PUT & DELETE., viewed ,<https://www.scien.cx/2021/04/14/rest-api-with-rust-warp-4-put-delete/>
VANCOUVER
Roger Torres | Sciencx - » REST API with Rust + Warp 4: PUT & DELETE. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/04/14/rest-api-with-rust-warp-4-put-delete/
CHICAGO
" » REST API with Rust + Warp 4: PUT & DELETE." Roger Torres | Sciencx - Accessed . https://www.scien.cx/2021/04/14/rest-api-with-rust-warp-4-put-delete/
IEEE
" » REST API with Rust + Warp 4: PUT & DELETE." Roger Torres | Sciencx [Online]. Available: https://www.scien.cx/2021/04/14/rest-api-with-rust-warp-4-put-delete/. [Accessed: ]
rf:citation
» REST API with Rust + Warp 4: PUT & DELETE | Roger Torres | Sciencx | https://www.scien.cx/2021/04/14/rest-api-with-rust-warp-4-put-delete/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.