1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
//! # Routes
//!
//! | METHOD | ROUTE | DESCRIPTION | RETURN |
//! |--------|---------------------|---------------------------------------------|--------------------------|
//! | GET | /api/v2/healthcheck | Used to check the health of the http server | (200, body: "OK") |
//! | GET | /api/v2/food | Get all row/food from the database | (200, body: JSON) or 500 |
//! | POST | /api/v2/food | Add food in the database | 204 or 500 |
//! | GET | /api/v2/food/:uuid | Get one row/food from the database | (200, body: JSON) or 500 |
//! | DELETE | /api/v2/food/:uuid | Delete on row/food in the database | 204 or 500 |
use axum::http::StatusCode;
use axum::routing::get;
use axum::{Extension, Router};
use sqlx::PgPool;
use crate::API_PREFIX;
pub mod error;
pub mod food;
pub mod handler;
/// Defines and returns the router of the app.
pub fn app(db: PgPool) -> Router {
Router::new()
// common route
.route(
format!("{API_PREFIX}/healthcheck").as_str(),
get(|| async { (StatusCode::OK, "OK") }),
)
// cleanup param route
//.route("/api/v2/cleanup/period", put(|| async { StatusCode::NOT_IMPLEMENTED })) // TODO
//.route("/api/v2/cleanup/expiration", put(|| async { StatusCode::NOT_IMPLEMENTED })) // TODO
// app route
.route(
format!("{API_PREFIX}/food").as_str(),
get(handler::list_food).post(handler::add_food),
)
.route(
format!("{API_PREFIX}/food/:id").as_str(),
get(handler::get_food)
//.put(handler::update_food), // TODO
.delete(handler::delete_food),
)
// Middleware
.layer(Extension(db)) // Share the db across handlers
}
#[cfg(test)]
mod tests {
use super::*;
use crate::db::get_db_url;
use axum::body::Body;
use axum::http::{Request, StatusCode};
use sqlx::postgres::PgPoolOptions;
use tower::util::ServiceExt;
#[tokio::test]
async fn axum_healthcheck() {
let db = PgPoolOptions::new()
.max_connections(5)
.connect(&get_db_url().unwrap())
.await
.unwrap();
let app = app(db);
// `Router` implements `tower::Service<Request<Body>>` so we can
// call it like any tower service, no need to run an HTTP server.
let response = app
.oneshot(
Request::builder()
.uri("/api/v2/healthcheck")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
assert_eq!(&body[..], b"OK");
}
#[tokio::test]
async fn axum_not_found() {
let db = PgPoolOptions::new()
.max_connections(5)
.connect(&get_db_url().unwrap())
.await
.unwrap();
let app = app(db);
let response = app
.oneshot(
Request::builder()
.uri("/does-not-exist")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
assert!(body.is_empty());
}
}