rust_api/lib.rs
1//! RustAPI: FastAPI-inspired REST framework for Rust
2//!
3//! RustAPI brings the developer experience of FastAPI and NestJS to Rust,
4//! with automatic OpenAPI generation, built-in validation, and dependency
5//! injection.
6//!
7//! # Features
8//!
9//! - **Route Macros**: Define endpoints with `#[get]`, `#[post]`, etc. The HTTP
10//! verb from the annotation is a binding contract — enforced at registration
11//! time via the `mount_handlers!` macro.
12//! - **Kleisli Pipeline**: `RouterPipeline` composes `Controller` Kleisli
13//! arrows with `and_then` (`>>=`), short-circuiting on any error.
14//! - **Direct DI**: Pass `Arc<Service>` directly to `pipeline.mount::<C>(svc)`.
15//! No type-map registry required for the primary use case.
16//! - **Type-Driven**: Leverage Rust's type system for validation and docs.
17//! - **Zero-Cost**: Built on Axum and Tokio for production performance.
18//!
19//! # Quick Start
20//!
21//! ```ignore
22//! use rust_api::prelude::*;
23//!
24//! pub struct UserController;
25//!
26//! #[get("/users")]
27//! pub async fn list_users(State(svc): State<Arc<UserService>>) -> Json<Vec<User>> {
28//! Json(svc.list())
29//! }
30//!
31//! mount_handlers!(UserController, UserService, [(__list_users_route, list_users)]);
32//!
33//! #[tokio::main]
34//! async fn main() {
35//! let svc = Arc::new(UserService::new());
36//!
37//! let app = RouterPipeline::new()
38//! .mount::<UserController>(svc)
39//! .map(|r| r.layer(TraceLayer::new_for_http()))
40//! .build()
41//! .unwrap();
42//!
43//! RustAPI::new(app).port(3000).serve().await.unwrap();
44//! }
45//! ```
46
47// Core modules
48pub mod app;
49pub mod controller;
50pub mod di;
51pub mod error;
52pub mod middleware;
53pub mod pipeline;
54pub mod router;
55pub mod server;
56
57// Re-export core types
58pub use app::App;
59pub use controller::Controller;
60pub use di::{Container, Injectable};
61pub use error::{Error, Result};
62pub use middleware::{guard, require_bearer};
63pub use pipeline::{RouterPipeline, RouterTransform};
64pub use router::{method_filter_from_str, ApiRoute, Router, RouterExt};
65pub use server::RustAPI;
66
67// Re-export routing methods from Axum (available for advanced use)
68pub mod routing {
69 pub use axum::routing::*;
70}
71
72// Re-export commonly used axum types.
73// Clients should never need to add `axum` as a direct dependency — all
74// surface types required to write handlers, extractors, and middleware
75// are available through this crate.
76pub use std::sync::Arc;
77
78pub use axum::{
79 extract::{FromRequestParts, Path, Query, State},
80 http::{header, request::Parts, StatusCode},
81 response::{IntoResponse, Response},
82 Json,
83};
84// Re-export macros
85pub use rust_api_macros::{delete, get, patch, post, put};
86// Re-export serde for user convenience
87pub use serde::{Deserialize, Serialize};
88pub use tower_http::{cors::CorsLayer, trace::TraceLayer};
89
90/// Generate a [`Controller`] implementation for a type from a handler list.
91///
92/// This macro produces the Kleisli arrow `Arc<State> -> (Router ->
93/// Result<Router>)` that the `RouterPipeline::mount` method threads through the
94/// pipeline.
95///
96/// Controllers using this macro have **zero dependency on `Router`, `RouteSet`,
97/// or any DI container** in their source files.
98///
99/// # Syntax
100///
101/// ```ignore
102/// mount_handlers!(ControllerType, ServiceType, [
103/// (__route_constant_1, handler_fn_1),
104/// (__route_constant_2, handler_fn_2),
105/// ]);
106/// ```
107///
108/// Where each `__route_constant` is the tuple `(&'static str, &'static str)`
109/// generated by a `#[get]`/`#[post]`/etc. annotation on the handler function.
110///
111/// # Example
112///
113/// ```ignore
114/// pub struct HealthController;
115///
116/// #[get("/health")]
117/// pub async fn health_check(State(svc): State<Arc<HealthService>>) -> Json<HealthResponse> {
118/// Json(svc.health_check())
119/// }
120///
121/// mount_handlers!(HealthController, HealthService, [
122/// (__health_check_route, health_check),
123/// ]);
124/// ```
125///
126/// Then in `main.rs`:
127///
128/// ```ignore
129/// RouterPipeline::new()
130/// .mount::<HealthController>(Arc::new(HealthService::new()))
131/// .build()?
132/// ```
133#[macro_export]
134macro_rules! mount_handlers {
135 // Entry: ControllerType, StateType, [ (route_const, handler), ... ]
136 ($controller:ty, $state:ty, [ $( ($route:expr, $handler:expr) ),* $(,)? ]) => {
137 impl $crate::controller::Controller for $controller {
138 type State = $state;
139
140 fn mount(
141 state: ::std::sync::Arc<$state>,
142 ) -> impl ::std::ops::FnOnce(
143 $crate::router::Router<()>,
144 ) -> $crate::error::Result<$crate::router::Router<()>> {
145 move |router| {
146 // Build a scoped router<Arc<State>> with one .route() per handler.
147 // The HTTP verb is read from the route constant — it is the
148 // annotation-enforced contract and cannot be overridden here.
149 let scoped: $crate::router::Router<::std::sync::Arc<$state>> =
150 $crate::router::Router::new()
151 $(
152 .route(
153 $route.0,
154 $crate::routing::on(
155 $crate::router::method_filter_from_str($route.1),
156 $handler,
157 ),
158 )
159 )*;
160 // Provide state (Router<Arc<State>> -> Router<()>) and merge.
161 Ok(router.merge(scoped.with_state(state)))
162 }
163 }
164 }
165 };
166}
167
168/// Prelude module for convenient imports.
169///
170/// Import everything you need with:
171/// ```ignore
172/// use rust_api::prelude::*;
173/// ```
174///
175/// # DI Note
176///
177/// [`Container`](crate::di::Container) is intentionally **not** in the prelude.
178/// The primary DI mechanism is direct `Arc<Service>` passing to
179/// `RouterPipeline::mount`. Import `Container` explicitly if you need a
180/// registry for large apps: `use rust_api::di::Container;`
181pub mod prelude {
182 pub use tokio;
183
184 pub use super::{
185 // Macros
186 delete,
187 get,
188 guard,
189 header,
190 patch,
191 post,
192 put,
193 require_bearer,
194 router,
195 // Router
196 ApiRoute,
197 App,
198 // Core types
199 Arc,
200 // Controller trait — visible for doc purposes; mount_handlers! generates impls.
201 Controller,
202 // Middleware
203 CorsLayer,
204 Deserialize,
205 Error,
206 // Axum — all surface types needed to write handlers and custom extractors.
207 // Clients must never add `axum` as a direct dependency.
208 FromRequestParts,
209 IntoResponse,
210 Json,
211 Parts,
212 Path,
213 Query,
214 Response,
215 Result,
216 Router,
217 RouterExt,
218 // Pipeline
219 RouterPipeline,
220 RouterTransform,
221 RustAPI,
222 // Serde
223 Serialize,
224 State,
225 StatusCode,
226 TraceLayer,
227 };
228 // Re-export the mount_handlers! macro so `use rust_api::prelude::*` brings it in.
229 pub use crate::mount_handlers;
230}