cargagep-v2/src/api/mod.rs
Antoine Pelletier 25b8d726e0 first commit
2026-08-23 16:53:16 +02:00

66 lines
1.8 KiB
Rust

//! HTTP layer: routing and OpenAPI generation (aide).
//!
//! Handlers stay thin: they extract the controller, call it, and map
//! `ControllerError` to a status code. No business logic here.
use std::sync::Arc;
use aide::{
OperationInput, OperationOutput,
axum::{ApiRouter, routing::get_with},
openapi::OpenApi,
};
use axum::{
Extension, Json, Router,
extract::FromRequestParts,
http::{StatusCode, request::Parts},
};
use tracing::error;
use crate::core::controller::AppController;
mod docs;
mod helpers;
mod items;
pub fn get_router(controller: AppController) -> Router {
aide::generate::on_error(|err| error!("aide generated error: {err}"));
aide::generate::extract_schemas(true);
let mut api = OpenApi::default();
ApiRouter::new()
.api_route(
"/api/version",
get_with(
async || Json(env!("CARGO_PKG_VERSION").to_string()),
|op| op.tag("misc").summary("Get app version"),
),
)
.nest_api_service("/api/items", items::routes())
.nest_api_service("/api/docs", docs::routes())
.finish_api_with(&mut api, docs::api_docs_metadata)
.layer(Extension(controller))
.layer(Extension(Arc::new(api)))
}
/// Lets a handler take an `AppController` as an argument
impl<S> FromRequestParts<S> for AppController
where
S: Send + Sync,
{
type Rejection = StatusCode;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
parts
.extensions
.get::<AppController>()
.cloned()
.ok_or(StatusCode::INTERNAL_SERVER_ERROR)
}
}
// The controller is not part of the request/response bodies: nothing to document
impl OperationOutput for AppController {
type Inner = Self;
}
impl OperationInput for AppController {}