6

In the Actix Web Framework, how does one use the route attributes macros (#[http_method("route")]) to bind multiple http methods to one function?

For example, I have this trivial endpoint:

/// Returns a UUID4.
#[get("/uuid")]
async fn uuid_v4() -> impl Responder {
    HttpResponse::Ok().json(Uuid {
        uuid: uuid::Uuid::new_v4(),
    })
}

I would like to have the same endpoint handle HEAD requests, how do I do this? My initial approach was to just stack up the macros:

/// Returns a UUID4.
#[get("/uuid")]
#[head("/uuid")]
async fn uuid_v4() -> impl Responder {
    HttpResponse::Ok().json(Uuid {
        uuid: uuid::Uuid::new_v4(),
    })
}

But I do get a compilation error:

    |
249 | async fn uuid_v4() -> impl Responder {
    |          ^^^^^^^ the trait `actix_web::handler::Factory<_, _, _>` is not implemented for `<uuid_v4 as actix_web::service::HttpServiceFactory>::register::uuid_v4`

I have gone through the actix-web and actix-web-codegen docs and didn't find anything addressing this

mattgathu
  • 1,129
  • 1
  • 19
  • 28

3 Answers3

7

you can do

#[route("/", method="GET", method="POST", method="PUT")]
async fn index() -> impl Responder {
  HttpResponse::Ok().body("Hello world!")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
  HttpServer::new(move || {
    App::new()
        .service(index)
  })
  .bind("127.0.0.1:8080")?
  .run()
  .await
}
tbounsiar
  • 199
  • 1
  • 9
7

An example with multiple path and multiple methods for one resource

async fn index() -> impl Responder {
  HttpResponse::Ok().body("Hello world!")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
  HttpServer::new(move || {
    App::new()
        .service(
            actix_web::web::resource(vec!["/", "/index"])
                .route(actix_web::web::get().to(index))
                .route(actix_web::web::post().to(index))
            )
  })
  .bind("127.0.0.1:8080")?
  .run()
  .await
}
Jbs Nice
  • 71
  • 1
  • 3
-2

I assume you are using actix-web: 2.0.0 with actix-rt: 1.0.0 and this handler you are passing to App.service method like below

HttpServer::new(move || {
            App::new()
                .wrap(middleware::Logger::default())
                .service(index)
        })
        .bind(("127.0.0.1", self.port))?
        .workers(8)
        .run()
        .await

then you will need to write handler like this ->

/// Returns a UUID4.
#[get("/uuid")]
async fn uuid_v4(req: HttpRequest) -> Result<web::Json<IndexResponse>> {
    let uuid_header = req
        .headers()
        .get("uuid")
        .and_then(|v| v.to_str().ok())
        .unwrap_or_else(|| "some-id");
    //curl -H "uuid: username" localhost:8080

    println!("make use of {}", uuid_header);
    Ok(web::Json(Uuid {
        uuid: uuid::Uuid::new_v4(),
    }))
}
STEEL
  • 8,955
  • 9
  • 67
  • 89