Skip to content

Instantly share code, notes, and snippets.

@641i130
Last active November 20, 2024 03:46
Show Gist options
  • Save 641i130/70bb89501c011e3646827db4cbf098d0 to your computer and use it in GitHub Desktop.
Save 641i130/70bb89501c011e3646827db4cbf098d0 to your computer and use it in GitHub Desktop.
actix web static mapping with functions
[package]
name = "mapactix"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4.9.0"
futures = "0.3.31"
phf = {version = "0.11.2", features = ["macros"]}
use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder};
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::sync::LazyLock;
// Define the handler function signature
type HandlerFn = dyn Fn(HttpRequest) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Error>>>> + Send + Sync;
// Define asynchronous handler functions
async fn handle_request_one(req: HttpRequest) -> Result<HttpResponse, Error> {
let query = req.query_string();
Ok(HttpResponse::Ok().body(format!("Handled by async function 1. Query: {}", query)))
}
async fn handle_request_two(req: HttpRequest) -> Result<HttpResponse, Error> {
let path = req.path();
Ok(HttpResponse::Ok().body(format!("Handled by async function 2. Path: {}", path)))
}
async fn handle_request_three(req: HttpRequest) -> Result<HttpResponse, Error> {
let headers = req.headers();
if headers.is_empty() {
return Err(actix_web::error::ErrorBadRequest("No headers found"));
}
Ok(HttpResponse::Ok().body(format!(
"Handled by async function 3. Headers: {:?}",
headers
)))
}
// Wrap async functions to match the `HandlerFn` signature
fn wrap_async_handler<F, Fut>(func: F) -> Box<HandlerFn>
where
F: Fn(HttpRequest) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<HttpResponse, Error>> + 'static,
{
Box::new(move |req| Box::pin(func(req)))
}
// Use LazyLock to defer initialization of the runtime map
static ROUTE_MAP: LazyLock<HashMap<&'static str, Box<HandlerFn>>> = LazyLock::new(|| {
let mut map: HashMap<&'static str, Box<HandlerFn>> = HashMap::new();
map.insert("1", wrap_async_handler(handle_request_one));
map.insert("2", wrap_async_handler(handle_request_two));
map.insert("3", wrap_async_handler(handle_request_three));
map
});
// Dynamic handler to route requests
async fn dynamic_handler(req: HttpRequest) -> impl Responder {
if let Some(number) = req.match_info().get("number") {
if let Some(handler) = ROUTE_MAP.get(number) {
return match handler(req).await {
Ok(response) => response,
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
};
}
}
HttpResponse::NotFound().body("No matching handler for this number")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/{number}", web::get().to(dynamic_handler))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment