Search code examples
rusturl-parametersactix-web

How do I define URL parameters in Actix-web?


In NodeJS, a route can be defined like:

app.get('/:x', (req, res) => {
  console.log(req.params.x)
  res.sendStatus(200)
});

Is there an Actix-web equivalent or a better recommended approach?

I want to upload a file with an id identifier, such that something like img.save(format!("{}.png", id)); could be written.

My current code for this:

use actix_multipart::Multipart;
use actix_web::{web, App, HttpServer, Responder};
use futures_util::{StreamExt, TryStreamExt};
use serde::Deserialize;
use image::ImageFormat;

async fn get() -> impl Responder {
    web::HttpResponse::Ok()
        .content_type("text/html; charset=utf-8")
        .body(include_str!("../page.html"))
}

async fn post(mut payload: Multipart) -> impl Responder {
    if let Ok(Some(mut field)) = payload.try_next().await {
        println!("field: {:.?}", field);

        let content_type = field.content_disposition();
        println!("content_type: {:.?}", content_type);

        if let Some(filename) = content_type.unwrap().get_filename() {
            println!("filename: {:.?}", filename);
        }

        let mut full_vec: Vec<u8> = Vec::new();
        while let Some(Ok(chunk)) = field.next().await {
            full_vec.append(&mut chunk.to_vec());
        }
        println!("full_vec: {}", full_vec.len());

        let img = image::load_from_memory_with_format(&full_vec, ImageFormat::Png)
            .expect("Image load error");
        img.save("img.png");
    }
    web::HttpResponse::Ok().finish()
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Started.");

    // Starts server
    HttpServer::new(move || {
        App::new()
            // Routes
            .route("/", web::get().to(get))
            .route("/", web::post().to(post))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

The HTML would be templated to have the ID in the form action (in the more general use case their may be multiple forms which have different ID's).

<!DOCTYPE html>
<html>
  <body>
    <!-- <form id="form" action="/<% id %>" method="post"> -->
    <form id="form" action="/" method="post">
      <input type="file" name="file" required><br>
      <input type="submit" value="Submit">
    </form>
  </body>
</html>

Solution

  • Using https://actix.rs/docs/extractors/.

    Change:

    1. async fn post(mut payload: Multipart)async fn post(path: web::Path<String>, mut payload: Multipart)
    2. .route("/", web::post().to(post)).route("/{id}", web::post().to(post))
    3. <form id="form" action="/" method="post"><form id="form" action="/someTestId" method="post">