notes/cmd/axum.md
2024-03-29 15:45:28 +01:00

1.8 KiB

Setup for axum serving static files and a rest API, using axum

  • took me a while to get right, but now it's no use anymore
  • assumes static files in ./assets
  • handles the mimetypes
  • the api may seem weird: it accepts a path param called rgb_hex and serves an image that is closest to that color (that code not here)
use axum::body::Body;
use axum::extract::Path;
use axum::http::{header, Request, StatusCode, Uri};
use axum::response::{IntoResponse, Response};
use axum::{routing::get, Router};
use spiegel_server::{get_closest_color, init};
use tower::ServiceExt;
use tower_http::services::ServeDir;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    tracing_subscriber::fmt::init();
    init();
    let app = Router::new()
        .route("/color/:rgb_hex", get(fetch_nearest_color))
        .nest_service("/", get(get_static_file));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
    Ok(())
}

async fn get_static_file(uri: Uri) -> Result<Response<Body>, (StatusCode, String)> {
    let req = Request::builder().uri(&uri).body(Body::empty()).unwrap();

    match ServeDir::new("assets").oneshot(req).await {
        Ok(res) => Ok(res.map(Body::new)),
        Err(err) => Err((
            StatusCode::INTERNAL_SERVER_ERROR,
            format!("Something went wrong: {}", err),
        )),
    }
}

async fn fetch_nearest_color(
    Path(rgb_hex): Path<String>,
) -> Result<impl IntoResponse, (StatusCode, String)> {
    if rgb_hex.len() != 6 {
        return Err((
            StatusCode::BAD_REQUEST,
            "input should be color hex, eg AA11CC".into(),
        ));
    }
    let closest = get_closest_color(&rgb_hex);

    let headers = [(header::CONTENT_TYPE, "image/jpeg")];
    Ok((headers, closest.image))
}