I'm currently trying to build an endpoint that will return an image (not in in bytes nor b64) to the user based on path but I cannot figure out how to do that with Axum and Rust.
The template of the method should look like that I guess:
#[derive(Deserialize)]
pub struct QueryParams {
path: String,
}
pub async fn get_image(
Query(QueryParams { path }): Query<QueryParams>
) -> impl IntoResponse {
}
And I already know the equivalent of what I want in C#
public ActionResult GetImage(string path)
{
FileExtensionContentTypeProvider fileProvider = new();
if (path.IsNullOrEmpty())
{
return NotFound("Parameter 'path' cannot be null or empty.");
}
if (!Directory.Exists(Path.GetDirectoryName(path)))
{
return NotFound($"Folder '{Path.GetDirectoryName(path)}' not found.");
}
if (!System.IO.File.Exists(path))
{
return NotFound($"File '{Path.GetFileName(path)}' not found.");
}
if (!fileProvider.TryGetContentType(path, out string? contentType))
{
throw new ArgumentException(
$"Could not determine MIME type of {Path.GetFileName(path)}.");
}
return PhysicalFile(path, contentType);
}
I already tried to use the crate image, tower-http with the ServeFile struct but I can't figure out how to make it work properly.
If anyone could provide me some explanation or help it would be greatly appreciated!
Here is the answer that came out from this discussion
#[derive(Deserialize)]
pub struct QueryParams {
path: String,
}
pub async fn get_image(
Query(QueryParams { path }): Query<QueryParams>
) -> impl IntoResponse {
let filename = match PathBuf::from(path).file_name() {
Some(name) => name,
None => return Err((StatusCode::BAD_REQUEST, "File name couldn't be determined".to_string()))
};
let file = match tokio::fs::File::open(path).await {
Ok(file) => file,
Err(err) => return Err((StatusCode::NOT_FOUND, format!("File not found: {}", err)))
};
let content_type = match mime_guess::from_path(&path).first_raw() {
Some(mime) => mime,
None => return Err((StatusCode::BAD_REQUEST, "MIME Type couldn't be determined".to_string()))
};
let stream = ReaderStream::new(file);
let body = StreamBody::new(stream);
let headers = [
(header::CONTENT_TYPE, content_type),
(
header::CONTENT_DISPOSITION,
&format!("attachment; filename=\"{:?}\"", filename),
),
];
Ok((headers, body))
}