66 lines
1.8 KiB
Rust
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 {}
|