rust-api 0.0.2

FastAPI-inspired REST framework for Rust with route macros, dependency injection, and automatic OpenAPI generation
Documentation
//! RustAPI: FastAPI-inspired REST framework for Rust
//!
//! RustAPI brings the developer experience of FastAPI and NestJS to Rust,
//! with automatic OpenAPI generation, built-in validation, and dependency
//! injection.
//!
//! # Features
//!
//! - **Route Macros**: Define endpoints with `#[get]`, `#[post]`, etc. The HTTP
//!   verb from the annotation is a binding contract — enforced at registration
//!   time via the `mount_handlers!` macro.
//! - **Kleisli Pipeline**: `RouterPipeline` composes `Controller` Kleisli
//!   arrows with `and_then` (`>>=`), short-circuiting on any error.
//! - **Direct DI**: Pass `Arc<Service>` directly to `pipeline.mount::<C>(svc)`.
//!   No type-map registry required for the primary use case.
//! - **Type-Driven**: Leverage Rust's type system for validation and docs.
//! - **Zero-Cost**: Built on Axum and Tokio for production performance.
//!
//! # Quick Start
//!
//! ```ignore
//! use rust_api::prelude::*;
//!
//! pub struct UserController;
//!
//! #[get("/users")]
//! pub async fn list_users(State(svc): State<Arc<UserService>>) -> Json<Vec<User>> {
//!     Json(svc.list())
//! }
//!
//! mount_handlers!(UserController, UserService, [(__list_users_route, list_users)]);
//!
//! #[tokio::main]
//! async fn main() {
//!     let svc = Arc::new(UserService::new());
//!
//!     let app = RouterPipeline::new()
//!         .mount::<UserController>(svc)
//!         .map(|r| r.layer(TraceLayer::new_for_http()))
//!         .build()
//!         .unwrap();
//!
//!     RustAPI::new(app).port(3000).serve().await.unwrap();
//! }
//! ```

// Core modules
pub mod app;
pub mod controller;
pub mod di;
pub mod error;
pub mod middleware;
pub mod pipeline;
pub mod router;
pub mod server;

// Re-export core types
pub use app::App;
pub use controller::Controller;
pub use di::{Container, Injectable};
pub use error::{Error, Result};
pub use middleware::{guard, require_bearer};
pub use pipeline::{RouterPipeline, RouterTransform};
pub use router::{method_filter_from_str, ApiRoute, Router, RouterExt};
pub use server::RustAPI;

// Re-export routing methods from Axum (available for advanced use)
pub mod routing {
    pub use axum::routing::*;
}

// Re-export commonly used axum types.
// Clients should never need to add `axum` as a direct dependency — all
// surface types required to write handlers, extractors, and middleware
// are available through this crate.
pub use std::sync::Arc;

pub use axum::{
    extract::{FromRequestParts, Path, Query, State},
    http::{header, request::Parts, StatusCode},
    response::{IntoResponse, Response},
    Json,
};
// Re-export macros
pub use rust_api_macros::{delete, get, patch, post, put};
// Re-export serde for user convenience
pub use serde::{Deserialize, Serialize};
pub use tower_http::{cors::CorsLayer, trace::TraceLayer};

/// Generate a [`Controller`] implementation for a type from a handler list.
///
/// This macro produces the Kleisli arrow `Arc<State> -> (Router ->
/// Result<Router>)` that the `RouterPipeline::mount` method threads through the
/// pipeline.
///
/// Controllers using this macro have **zero dependency on `Router`, `RouteSet`,
/// or any DI container** in their source files.
///
/// # Syntax
///
/// ```ignore
/// mount_handlers!(ControllerType, ServiceType, [
///     (__route_constant_1, handler_fn_1),
///     (__route_constant_2, handler_fn_2),
/// ]);
/// ```
///
/// Where each `__route_constant` is the tuple `(&'static str, &'static str)`
/// generated by a `#[get]`/`#[post]`/etc. annotation on the handler function.
///
/// # Example
///
/// ```ignore
/// pub struct HealthController;
///
/// #[get("/health")]
/// pub async fn health_check(State(svc): State<Arc<HealthService>>) -> Json<HealthResponse> {
///     Json(svc.health_check())
/// }
///
/// mount_handlers!(HealthController, HealthService, [
///     (__health_check_route, health_check),
/// ]);
/// ```
///
/// Then in `main.rs`:
///
/// ```ignore
/// RouterPipeline::new()
///     .mount::<HealthController>(Arc::new(HealthService::new()))
///     .build()?
/// ```
#[macro_export]
macro_rules! mount_handlers {
    // Entry: ControllerType, StateType, [ (route_const, handler), ... ]
    ($controller:ty, $state:ty, [ $( ($route:expr, $handler:expr) ),* $(,)? ]) => {
        impl $crate::controller::Controller for $controller {
            type State = $state;

            fn mount(
                state: ::std::sync::Arc<$state>,
            ) -> impl ::std::ops::FnOnce(
                $crate::router::Router<()>,
            ) -> $crate::error::Result<$crate::router::Router<()>> {
                move |router| {
                    // Build a scoped router<Arc<State>> with one .route() per handler.
                    // The HTTP verb is read from the route constant — it is the
                    // annotation-enforced contract and cannot be overridden here.
                    let scoped: $crate::router::Router<::std::sync::Arc<$state>> =
                        $crate::router::Router::new()
                        $(
                            .route(
                                $route.0,
                                $crate::routing::on(
                                    $crate::router::method_filter_from_str($route.1),
                                    $handler,
                                ),
                            )
                        )*;
                    // Provide state (Router<Arc<State>> -> Router<()>) and merge.
                    Ok(router.merge(scoped.with_state(state)))
                }
            }
        }
    };
}

/// Prelude module for convenient imports.
///
/// Import everything you need with:
/// ```ignore
/// use rust_api::prelude::*;
/// ```
///
/// # DI Note
///
/// [`Container`](crate::di::Container) is intentionally **not** in the prelude.
/// The primary DI mechanism is direct `Arc<Service>` passing to
/// `RouterPipeline::mount`. Import `Container` explicitly if you need a
/// registry for large apps: `use rust_api::di::Container;`
pub mod prelude {
    pub use tokio;

    pub use super::{
        // Macros
        delete,
        get,
        guard,
        header,
        patch,
        post,
        put,
        require_bearer,
        router,
        // Router
        ApiRoute,
        App,
        // Core types
        Arc,
        // Controller trait — visible for doc purposes; mount_handlers! generates impls.
        Controller,
        // Middleware
        CorsLayer,
        Deserialize,
        Error,
        // Axum — all surface types needed to write handlers and custom extractors.
        // Clients must never add `axum` as a direct dependency.
        FromRequestParts,
        IntoResponse,
        Json,
        Parts,
        Path,
        Query,
        Response,
        Result,
        Router,
        RouterExt,
        // Pipeline
        RouterPipeline,
        RouterTransform,
        RustAPI,
        // Serde
        Serialize,
        State,
        StatusCode,
        TraceLayer,
    };
    // Re-export the mount_handlers! macro so `use rust_api::prelude::*` brings it in.
    pub use crate::mount_handlers;
}