Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.checkOnSave": false
}
61 changes: 61 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ async fn main() {
let app = Router::new()
.route("/", get(|| async move { "welcome to Image upload api" }))
.route("/upload", post(upload_image))
.route("/upload/master", post(upload_image_no_timestamp))
.layer(cors_layer)
.layer(Extension(aws_s3_client))
.layer(axum::middleware::from_fn(log_request_ip));
Expand Down Expand Up @@ -113,3 +114,63 @@ async fn upload_image(
// send the urls in response
Ok(Json(serde_json::json!(res)))
}


async fn upload_image_no_timestamp(
Extension(s3_client): Extension<Client>,
mut files: Multipart,
) -> Result<Json<serde_json::Value>, (StatusCode, Json<serde_json::Value>)> {
// get the name of aws bucket from env variable
let bucket = std::env::var("AWS_S3_BUCKET").unwrap_or_else(|_| "my-bucket-name".to_owned());
// if you have a public url for your bucket, place it as ENV variable BUCKET_URL
let bucket_url = std::env::var("BUCKET_URL").unwrap_or_else(|_| bucket.to_owned());
// if a sub folder path is set in environment then get that else set a default sub path
let sub_path = std::env::var("BUCKET_SUB_PATH").unwrap_or_else(|_| "uploaded_images".to_owned());
// we are going to store the respose in HashMap as filename: url => key: value
let mut res = HashMap::new();
while let Some(file) = files.next_field().await.unwrap() {
// this is the name which is sent in formdata from frontend or whoever called the api, i am
// using it as category, we can get the filename from file data
let category = file.name().unwrap().to_string();
// name of the file with extention
let name = file.file_name().unwrap().to_string();
// file data
let data = file.bytes().await.unwrap();
// the request can control where to save the image on AWS S3
let request_path = if category.trim().is_empty() {"".to_owned()} else {format!("{}/", &category.trim_end_matches('/'))};
// the path of file to store on aws s3 with file name and extention
// timestamp_category_filename => 14-12-2022_01:01:01_customer_somecustomer.jpg
let key = format!(
"{}/images/{}_{}_{}",
sub_path,
&request_path,
&category,
&name
);

// send Putobject request to aws s3
let _resp = s3_client
.put_object()
.bucket(&bucket)
.key(&key)
.body(data.into())
.send()
.await
.map_err(|err| {
dbg!(err);
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(serde_json::json!({"err": "an error occured during image upload"})),
)
})?;
dbg!(_resp);
res.insert(
// concatinating name and category so even if the filenames are same it will not
// conflict
format!("{}_{}", &name, &category),
format!("{}/{}", bucket_url, key),
);
}
// send the urls in response
Ok(Json(serde_json::json!(res)))
}