Skip to main content

fastapi_rust/
lib.rs

1//! Ultra-optimized Rust web framework inspired by FastAPI.
2//!
3//! fastapi_rust provides a type-safe, high-performance web framework with:
4//!
5//! - **Type-driven API design** — Route handlers declare types, framework extracts/validates automatically
6//! - **Dependency injection** — Composable, testable request handling
7//! - **Automatic OpenAPI** — Schema generation from type definitions
8//! - **First-class async** — Built on asupersync for structured concurrency
9//! - **Minimal dependencies** — Only asupersync + serde
10//!
11//! # Role In The System
12//!
13//! `fastapi_rust` is the user-facing facade crate. It re-exports the framework's
14//! core types, macros, and utilities from the sub-crates so applications only
15//! need a single dependency. All real behavior lives in the sub-crates listed
16//! below; this crate exists to provide a cohesive, ergonomic API surface.
17//!
18//! # Quick Start
19//!
20//! ```ignore
21//! use fastapi_rust::prelude::*;
22//!
23//! #[derive(Serialize, Deserialize, JsonSchema)]
24//! struct Item {
25//!     id: i64,
26//!     name: String,
27//! }
28//!
29//! #[get("/items/{id}")]
30//! async fn get_item(cx: &Cx, id: Path<i64>) -> Json<Item> {
31//!     Json(Item { id: id.0, name: "Example".into() })
32//! }
33//!
34//! fn main() {
35//!     let app = App::new()
36//!         .title("My API")
37//!         .route(get_item);
38//!
39//!     // Run with asupersync
40//!     // asupersync::block_on(app.serve("0.0.0.0:8000"));
41//! }
42//! ```
43//!
44//! # Design Philosophy
45//!
46//! This framework is built with the following principles:
47//!
48//! 1. **Zero-cost abstractions** — No runtime reflection, everything at compile time
49//! 2. **Cancel-correct** — Leverages asupersync's structured concurrency
50//! 3. **Minimal allocations** — Zero-copy parsing where possible
51//! 4. **Familiar API** — FastAPI users will recognize the patterns
52//!
53//! # Crate Structure
54//!
55//! | Crate | Purpose |
56//! |-------|---------|
57//! | `fastapi_core` | Core types (Request, Response, Error), extractors, middleware, DI |
58//! | `fastapi_http` | Zero-copy HTTP/1.1 parser, TCP server, chunked encoding |
59//! | `fastapi_router` | Trie-based router with O(log n) lookups |
60//! | `fastapi_macros` | Procedural macros (`#[get]`, `#[derive(Validate)]`, `#[derive(JsonSchema)]`) |
61//! | `fastapi_openapi` | OpenAPI 3.1 schema types and generation |
62//! | `fastapi_output` | Agent-aware rich console output (optional) |
63//!
64//! # Feature Flags
65//!
66//! | Feature | Default | Description |
67//! |---------|---------|-------------|
68//! | `output` | **yes** | Rich console output with agent detection (includes `fastapi-output/rich`) |
69//! | `output-plain` | no | Plain-text-only output (smaller binary, no ANSI codes) |
70//! | `full` | no | All output features including every theme and component |
71//!
72//! ## Sub-crate Feature Flags
73//!
74//! **`fastapi-core`:**
75//!
76//! | Feature | Description |
77//! |---------|-------------|
78//! | `regex` | Regex support in testing assertions |
79//! | `compression` | Response compression middleware (gzip via flate2) |
80//! | `proptest` | Property-based testing support |
81
82//!
83//! # Cookbook
84//!
85//! Common patterns for building APIs with fastapi_rust.
86//!
87//! ## JSON CRUD Handler
88//!
89//! ```ignore
90//! use fastapi_rust::prelude::*;
91//!
92//! #[get("/items/{id}")]
93//! async fn get_item(cx: &Cx, id: Path<i64>, state: State<AppState>) -> Result<Json<Item>, HttpError> {
94//!     let item = state.db.find(id.0).await?;
95//!     Ok(Json(item))
96//! }
97//! ```
98//!
99//! ## Pagination
100//!
101//! ```ignore
102//! use fastapi_rust::prelude::*;
103//!
104//! #[get("/items")]
105//! async fn list_items(cx: &Cx, page: Pagination) -> Json<Page<Item>> {
106//!     // page.page() returns current page (default: 1)
107//!     // page.per_page() returns items per page (default: 20, max: 100)
108//!     let items = db.list(page.offset(), page.limit()).await;
109//!     Json(Page::new(items, total_count, page.page(), page.per_page()))
110//! }
111//! ```
112//!
113//! ## Bearer Token Authentication
114//!
115//! ```ignore
116//! use fastapi_rust::prelude::*;
117//!
118//! #[get("/protected")]
119//! async fn protected(cx: &Cx, token: BearerToken) -> Json<UserInfo> {
120//!     let user = verify_jwt(token.token()).await?;
121//!     Json(user)
122//! }
123//! ```
124//!
125//! ## Background Tasks
126//!
127//! ```ignore
128//! use fastapi_rust::prelude::*;
129//!
130//! #[post("/send-email")]
131//! async fn send_email(cx: &Cx, body: Json<EmailRequest>, tasks: BackgroundTasks) -> StatusCode {
132//!     tasks.add(move || {
133//!         // Runs after response is sent
134//!         email_service::send(&body.to, &body.subject, &body.body);
135//!     });
136//!     StatusCode::ACCEPTED
137//! }
138//! ```
139//!
140//! ## CORS + Rate Limiting Middleware
141//!
142//! ```ignore
143//! use fastapi_rust::prelude::*;
144//!
145//! let app = App::new()
146//!     .middleware(Cors::new().allow_any_origin(true).allow_credentials(true))
147//!     .middleware(RateLimitBuilder::new().max_requests(100).window_secs(60).build());
148//! ```
149//!
150//! ## Error Handling
151//!
152//! ```ignore
153//! use fastapi_rust::prelude::*;
154//!
155//! // Custom errors implement IntoResponse automatically via HttpError
156//! fn not_found(resource: &str, id: u64) -> HttpError {
157//!     HttpError::not_found(format!("{} {} not found", resource, id))
158//! }
159//! ```
160//!
161//! # Migrating from Python FastAPI
162//!
163//! ## Key Differences
164//!
165//! | Python FastAPI | fastapi_rust | Notes |
166//! |----------------|--------------|-------|
167//! | `@app.get("/")` | `#[get("/")]` | Proc macro instead of decorator |
168//! | `async def handler(item: Item)` | `async fn handler(cx: &Cx, item: Json<Item>)` | Explicit `Cx` context + typed extractors |
169//! | `Depends(get_db)` | `Depends<DbPool>` | Type-based DI, not function-based |
170//! | `HTTPException(404)` | `HttpError::not_found(msg)` | Typed error constructors |
171//! | `BackgroundTasks` | `BackgroundTasks` | Same concept, different API |
172//! | `Query(q: str)` | `Query<SearchParams>` | Struct-based query extraction |
173//! | `Path(item_id: int)` | `Path<i64>` | Type-safe path parameters |
174//! | `Body(...)` | `Json<T>` | Explicit JSON extraction |
175//! | `Response(status_code=201)` | `StatusCode::CREATED` | Type-safe status codes |
176//!
177//! ## Async Runtime
178//!
179//! Python FastAPI uses `asyncio`. fastapi_rust uses `asupersync`, which provides:
180//! - **Structured concurrency**: Request handlers run in regions
181//! - **Cancel-correctness**: Graceful cancellation via checkpoints
182//! - **Budgeted timeouts**: Request timeouts via budget exhaustion
183//!
184//! Every handler receives `&Cx` as its first parameter for async context.
185//!
186//! ## Dependency Injection
187//!
188//! Python uses function-based DI with `Depends(func)`. Rust uses trait-based DI:
189//!
190//! ```ignore
191//! // Python:
192//! // async def get_db():
193//! //     yield db_session
194//! //
195//! // @app.get("/")
196//! // async def handler(db: Session = Depends(get_db)):
197//!
198//! // Rust:
199//! impl FromDependency for DbPool {
200//!     async fn from_dependency(cx: &Cx, cache: &DependencyCache) -> Result<Self, HttpError> {
201//!         Ok(DbPool::acquire(cx).await?)
202//!     }
203//! }
204//!
205//! #[get("/")]
206//! async fn handler(cx: &Cx, db: Depends<DbPool>) -> Json<Data> { ... }
207//! ```
208//!
209//! ## Validation
210//!
211//! Python uses Pydantic models. Rust uses `#[derive(Validate)]`:
212//!
213//! ```ignore
214//! // Python:
215//! // class Item(BaseModel):
216//! //     name: str = Field(..., min_length=1, max_length=100)
217//! //     price: float = Field(..., gt=0)
218//!
219//! // Rust:
220//! #[derive(Validate)]
221//! struct Item {
222//!     #[validate(min_length = 1, max_length = 100)]
223//!     name: String,
224//!     #[validate(range(min = 0.01))]
225//!     price: f64,
226//! }
227//! ```
228
229#![forbid(unsafe_code)]
230// Design doc at PROPOSED_RUST_ARCHITECTURE.md (not embedded - too many conceptual code examples)
231
232// Re-export crates
233pub use fastapi_core as core;
234pub use fastapi_http as http;
235pub use fastapi_macros as macros;
236pub use fastapi_openapi as openapi;
237pub use fastapi_router as router;
238
239// Re-export commonly used types
240pub use fastapi_core::{
241    App, AppBuilder, AppConfig, ConfigError, Cors, CorsConfig, DefaultConfig,
242    DefaultDependencyConfig, DependencyOverrides, DependencyScope, Depends, DependsConfig,
243    FromDependency, FromRequest, HttpError, IntoResponse, Method, NoCache, Request, RequestId,
244    RequestIdConfig, RequestIdMiddleware, Response, ResponseBody, StateContainer, StatusCode,
245    ValidationError, ValidationErrors,
246};
247
248// Re-export extractors
249pub use fastapi_core::{
250    // Common header types
251    Accept,
252    AddResponseHeader,
253    AppState,
254    Authorization,
255    // Background tasks
256    BackgroundTasks,
257    BackgroundTasksInner,
258    // Auth extractors
259    BasicAuth,
260    BasicAuthError,
261    BearerToken,
262    BearerTokenError,
263    ContentType,
264    // Cookies
265    Cookie,
266    CookiePrefix,
267    CookiePrefixError,
268    DEFAULT_PAGE,
269    DEFAULT_PER_PAGE,
270    // Headers
271    Header,
272    HeaderExtractError,
273    HeaderValues,
274    Host,
275    // Body extractors
276    Json,
277    JsonConfig,
278    JsonExtractError,
279    MAX_PER_PAGE,
280    NamedHeader,
281    OAuth2BearerError,
282    OAuth2PasswordBearer,
283    OAuth2PasswordBearerConfig,
284    Page,
285    // Pagination
286    Pagination,
287    PaginationConfig,
288    // Path parameters
289    Path,
290    PathExtractError,
291    PathParams,
292    // Query string
293    Query,
294    QueryExtractError,
295    QueryParams,
296    RequestContext,
297    RequestCookies,
298    // Request utilities
299    RequestRef,
300    // Response mutations
301    ResponseMut,
302    ResponseMutations,
303    SameSite,
304    // State
305    State,
306    UserAgent,
307    XRequestId,
308};
309
310// Re-export testing utilities
311pub use fastapi_core::{CookieJar, RequestBuilder, TestClient, TestResponse};
312pub use fastapi_macros::{JsonSchema, Validate, delete, get, head, options, patch, post, put};
313pub use fastapi_openapi::{OpenApi, OpenApiBuilder, SchemaRegistry};
314pub use fastapi_router::{
315    // Route matching
316    AllowedMethods,
317    ConversionError,
318    // Path parameter types
319    Converter,
320    // Error types
321    InvalidRouteError,
322    ParamInfo,
323    ParamValue,
324    // Core router types
325    Route,
326    RouteAddError,
327    RouteConflictError,
328    RouteLookup,
329    RouteMatch,
330    Router,
331};
332
333// Re-export HTTP server types
334pub use fastapi_http::{
335    GracefulOutcome, ServeError, Server, ServerConfig, ServerError, ShutdownController,
336    ShutdownReceiver, TcpServer, serve, serve_with_config,
337};
338
339/// Prelude module for convenient imports.
340pub mod prelude {
341    pub use crate::{
342        // Core types
343        App,
344        AppBuilder,
345        AppConfig,
346        // Auth
347        BasicAuth,
348        BearerToken,
349        ConfigError,
350        Cookie,
351        Cors,
352        CorsConfig,
353        DefaultConfig,
354        DefaultDependencyConfig,
355        DependencyOverrides,
356        DependencyScope,
357        Depends,
358        DependsConfig,
359        FromDependency,
360        FromRequest,
361        Header,
362        HttpError,
363        IntoResponse,
364        // Extractors
365        Json,
366        // Macros
367        JsonSchema,
368        Method,
369        NoCache,
370        OAuth2PasswordBearer,
371        // OpenAPI
372        OpenApi,
373        OpenApiBuilder,
374        Page,
375        // Pagination
376        Pagination,
377        Path,
378        Query,
379        Request,
380        RequestContext,
381        RequestId,
382        RequestIdMiddleware,
383        Response,
384        Route,
385        Router,
386        // Server
387        Server,
388        ServerConfig,
389        State,
390        StatusCode,
391        Validate,
392        ValidationError,
393        ValidationErrors,
394        delete,
395        get,
396        head,
397        options,
398        patch,
399        post,
400        put,
401        serve,
402    };
403    pub use serde::{Deserialize, Serialize};
404}
405
406/// Testing utilities module.
407pub mod testing {
408    pub use fastapi_core::testing::{CookieJar, RequestBuilder, TestClient, TestResponse};
409}
410
411/// Extractors module for type-safe request data extraction.
412pub mod extractors {
413    pub use fastapi_core::{
414        Accept, AppState, Authorization, BackgroundTasks, BasicAuth, BearerToken, ContentType,
415        Cookie, Header, HeaderValues, Host, Json, JsonConfig, NamedHeader, OAuth2PasswordBearer,
416        Page, Pagination, PaginationConfig, Path, PathParams, Query, QueryParams, RequestRef,
417        ResponseMut, ResponseMutations, State, UserAgent, XRequestId,
418    };
419}
420
421/// HTTP server module with server types and configuration.
422pub mod server {
423    pub use fastapi_http::{
424        // Configuration constants
425        DEFAULT_DRAIN_TIMEOUT_SECS,
426        DEFAULT_KEEP_ALIVE_TIMEOUT_SECS,
427        DEFAULT_MAX_CONNECTIONS,
428        DEFAULT_MAX_REQUESTS_PER_CONNECTION,
429        DEFAULT_READ_BUFFER_SIZE,
430        DEFAULT_REQUEST_TIMEOUT_SECS,
431        // Shutdown coordination
432        GracefulOutcome,
433        // Error types
434        ServeError,
435        // Server types
436        Server,
437        ServerConfig,
438        ServerError,
439        ShutdownController,
440        ShutdownReceiver,
441        TcpServer,
442        // Server functions
443        serve,
444        serve_with_config,
445    };
446}