bobashare_web/api/v1/
mod.rs

1//! Version 1 of the bobashare API, hosted at `/api/v1/`
2
3use std::error::Error;
4
5use axum::{
6    response::{IntoResponse, Response},
7    routing::{delete, get, put},
8    Json, Router,
9};
10use hyper::StatusCode;
11use serde_json::json;
12use tracing::{event, Level};
13
14use crate::AppState;
15
16pub mod delete;
17pub mod info;
18pub mod upload;
19
20/// Routes under `/api/v1/`
21///
22/// - `/api/v1/info/:id`: [`info::info`]
23/// - `/api/v1/upload`: [`upload::put`]
24/// - `/api/v1/upload/:filename`: [`upload::put`]
25/// - `/api/v1/delete/:id`: [`delete::delete`]
26pub fn router() -> Router<&'static AppState> {
27    Router::new()
28        .route("/info/{id}", get(info::info))
29        .route("/upload/{filename}", put(upload::put))
30        .route("/delete/{id}", delete(delete::delete))
31}
32
33/// Method to convert an [`std::error::Error`] into a [`Response`] with a
34/// specified [`StatusCode`]
35pub trait ApiErrorExt: Error + Sized + Send + Sync + 'static {
36    /// Consume the error and convert it to a [`Response`] with the specified
37    /// [`StatusCode`]
38    fn into_response_with_code(self, code: StatusCode) -> Response {
39        let mut error_msg = self.to_string(); // does not include causes
40
41        let mut err_buf = self.source();
42        while let Some(e) = err_buf {
43            error_msg += &format!(": {e}");
44            err_buf = e.source();
45        }
46
47        if code.is_server_error() {
48            event!(Level::ERROR, status = code.as_u16(), error = error_msg);
49        } else if code.is_client_error() {
50            event!(Level::WARN, status = code.as_u16(), error = error_msg);
51        } else {
52            event!(Level::INFO, status = code.as_u16(), error = error_msg);
53        }
54
55        let resp = json!({
56            "status": "error",
57            "error": serde_error::Error::new(&self),
58            "message": error_msg,
59        });
60        (code, Json(resp)).into_response()
61    }
62}
63impl<T> ApiErrorExt for T where T: Error + Send + Sync + 'static {}