Skip to main content

xitca_web/
lib.rs

1//! a web framework focused on memory efficiency, composability, and fast compile time.
2//!
3//! # Quick start
4//! ```no_run
5//! use xitca_web::{handler::handler_service, route::get, App};
6//!
7//! fn main() -> std::io::Result<()> {
8//!     App::new()
9//!         .at("/", get(handler_service(async || "Hello,World!")))
10//!         .serve()
11//!         .bind("localhost:8080")?
12//!         .run()
13//!         .wait()
14//! }
15//! ```
16//!
17//! # Feature flags
18//! Most features are disabled by default and can be enabled selectively in your `Cargo.toml`.
19//!
20//! ## HTTP versions
21//! - **`http1`** *(default)* — HTTP/1.1 server support.
22//! - **`http2`** — HTTP/2 server support.
23//! - **`http3`** — HTTP/3 (QUIC) server support.
24//!
25//! ## IO
26//! - **`io-uring`** — Linux io-uring based async IO for the server runtime.
27//!
28//! ## TLS
29//! - **`openssl`** — TLS via OpenSSL.
30//! - **`rustls`** — TLS via Rustls.
31//!
32//! ## Extractors / Responders
33//! - **`params`** — Path parameters type extractor (enables `serde`).
34//! - **`json`** — JSON type extractor/responder (enables `serde`).
35//! - **`urlencoded`** — URL-encoded form type extractor (enables `serde`).
36//! - **`multipart`** — Multipart form data type extractor.
37//! - **`grpc`** — gRPC type extractor/responder (via `prost`).
38//! - **`websocket`** — WebSocket type extractor/responder.
39//! - **`cookie`** — Cookie handler type.
40//!
41//! ## Compression middlewares
42//! - **`compress-br`** — Brotli (de)compression.
43//! - **`compress-gz`** — Gzip (de)compression.
44//! - **`compress-de`** — Deflate (de)compression.
45//! - **`compress-zs`** — Zstd (de)compression.
46//!
47//! ## Static file serving
48//! - **`file`** — Static file serving with default file system backend.
49//! - **`file-io-uring`** — Static file serving using io-uring (implies `io-uring` and `file`).
50//! - **`file-raw`** — Static file serving without a default file system backend.
51//!
52//! ## Middleware
53//! - **`rate-limit`** — Rate-limiting middleware.
54//! - **`logger`** — Tracing/logging middleware (via `tracing` and `tracing-subscriber`).
55//!
56//! ## Codegen
57//! - **`codegen`** — Proc-macro code generation (`#[route]`, `#[derive(State)]`, etc.).
58//!
59//! ## Interop
60//! - **`tower-http-compat`** — Compatibility layer for using `tower-http` services and layers.
61//!
62//! ## Other
63//! - **`serde`** — Shared (de)serialization support. Automatically enabled by `params`, `json`, and `urlencoded`.
64//! - **`nightly`** — Enables nightly-only Rust features. **Unstable** — breaking changes to nightly-gated
65//!   APIs are not considered semver-breaking.
66//!
67//! # Memory efficient
68//! - zero copy magic types
69//! - zero cost service tree
70//!
71//! ## Zero copy
72//! ```rust
73//! # #[cfg(feature = "json")]
74//! # fn _main() -> std::io::Result<()> {
75//! use xitca_web::{
76//!     error::Error,
77//!     handler::{handler_service, json::LazyJson, path::PathRef},
78//!     route::{get, post},
79//!     App
80//! };
81//!
82//! // PathRef is able to borrow http request's path string as reference
83//! // without copying it.
84//! async fn url_query(PathRef(path): PathRef<'_>) -> &'static str {
85//!     println!("{path}");
86//!     "zero copy path"    
87//! }
88//!
89//! // deserializable user type.
90//! #[derive(serde::Deserialize)]
91//! struct User<'a> {
92//!     name: &'a str
93//! }
94//!
95//! // LazyJson is able to lazily deserialize User type with zero copy &str.
96//! async fn json(lazy: LazyJson<User<'_>>) -> Result<&'static str, Error> {
97//!     let User { name } = lazy.deserialize()?;
98//!     println!("{name}");
99//!     Ok("zero copy json")    
100//! }
101//!
102//! // Almost all magic extract types in xitca-web utilize zero copy
103//! // to avoid unnecessary memory copy.
104//! App::new()
105//!     // a route handling incoming url query.
106//!     .at("/query", get(handler_service(url_query)))
107//!     // a route handling incoming json object.
108//!     .at("/json", post(handler_service(json)))
109//!     .serve()
110//!     .bind("localhost:8080")?
111//!     .run()
112//!     .wait()
113//! # }
114//! ```
115//!
116//! ## Zero cost
117//! ```rust
118//! use xitca_web::{
119//!     handler::{handler_service},
120//!     http::WebResponse,
121//!     route::get,
122//!     middleware::Extension,
123//!     service::{Service, ServiceExt},
124//!     App, WebContext
125//! };
126//! # fn _main() -> std::io::Result<()> {
127//! App::new()
128//!     .at("/", get(handler_service(|| async { "hello,world!" })))
129//!     // ServiceExt::enclosed_fn combinator enables async function as middleware.
130//!     // the async function is unboxed and potentially inlined with other async services
131//!     // for efficient binary code with less memory allocation.
132//!     .enclosed_fn(middleware_fn)
133//!     // ServiceExt::enclosed combinator enables type impl Service trait as middleware.
134//!     // the middleware trait method is unboxed and potentially inlined with other async services
135//!     // for efficient binary code with less memory allocation.
136//!     .enclosed(Extension::new(()))
137//!     .serve()
138//!     .bind("localhost:8080")?
139//!     .run()
140//!     .wait()
141//! # }
142//!
143//! // a simple middleware just forward request to inner service logic.
144//! async fn middleware_fn<S, T, E>(service: &S, ctx: WebContext<'_>) -> Result<T, E>
145//! where
146//!     S: for<'r> Service<WebContext<'r>, Response = T, Error = E>
147//! {
148//!     service.call(ctx).await
149//! }
150//! ```
151//!
152//! # Composable
153//! - Easy mixture of various level of abstractions and less opinionated APIs
154//! - Common types and traits for cross crates integration of majority rust web ecosystem
155//!
156//! ## Abstraction variety
157//! ```rust
158//! use xitca_web::{
159//!     body::ResponseBody,
160//!     error::Error,
161//!     handler::{handler_service, handler_sync_service, Responder},
162//!     http::{Method, WebResponse},
163//!     route::get,
164//!     service::fn_service,
165//!     App, WebContext
166//! };
167//!
168//! # fn _main() -> std::io::Result<()> {
169//! App::new()
170//!     // high level abstraction. see fn high for detail.
171//!     .at("/high", get(handler_service(high)))
172//!     // low level abstraction. see fn low for detail.
173//!     .at("/low", get(fn_service(low)))
174//!     // abstraction for synchronous. see fn sync for detail.
175//!     .at("/sync", get(handler_sync_service(sync)))
176//!     .serve()
177//!     .bind("localhost:8080")?
178//!     .run()
179//!     .wait()
180//! # }
181//!
182//! // magic function with arbitrary receiver type and output type
183//! // that can be extracted from http requests and packed into http
184//! // response.
185//! async fn high(method: &Method) -> &'static str {
186//!     // extract http method from http request.
187//!     assert_eq!(method, Method::GET);
188//!     // pack string literal into http response.
189//!     "high level"     
190//! }
191//!
192//! // function with concrete typed input and output where http types
193//! // are handled manually and explicitly.
194//! // it can also be seen as a desugar of previous example of
195//! // handler_service(high)
196//! async fn low(ctx: WebContext<'_>) -> Result<WebResponse, Error> {
197//!     // extract method from request context.
198//!     let method = ctx.extract().await?;
199//!     // execute high level abstraction example function.
200//!     let str = high(method).await;
201//!     // convert string literal to http response.
202//!     str.respond(ctx).await
203//! }
204//!
205//! // high level abstraction but for synchronous function. this function
206//! // is powered by background thread pool so it does not block the async
207//! // code.
208//! fn sync(method: Method) -> &'static str {
209//!     assert_eq!(method, Method::GET);
210//!     // blocking thread for long period of time does not impact xitca-web
211//!     // async internal.
212//!     std::thread::sleep(std::time::Duration::from_secs(3));
213//!     "sync"    
214//! }
215//! ```
216//!
217//! ## Middleware composability
218//! ```rust
219//! use xitca_web::{
220//!     error::Error,
221//!     handler::{handler_service},
222//!     http::WebResponse,
223//!     route::get,
224//!     service::{Service, ServiceExt},
225//!     App, WebContext
226//! };
227//!
228//! # fn _main() -> std::io::Result<()> {
229//! // ServiceExt::enclosed_fn combinator enables async function as middleware.
230//! // in xitca_web almost all service can be enclosed by an middleware.
231//! App::new()
232//!     .at("/",
233//!         get(
234//!             // apply middleware to handler_service
235//!             handler_service(|| async { "hello,world!" })
236//!                 .enclosed_fn(middleware_fn)
237//!         )
238//!         // apply middleware to route
239//!         .enclosed_fn(middleware_fn)
240//!     )
241//!     // apply middleware to application
242//!     .enclosed_fn(middleware_fn)
243//!     .serve()
244//!     .bind("localhost:8080")?
245//!     .run()
246//!     .wait()
247//! # }
248//!
249//! // a simple middleware just forward request to inner service logic.
250//! async fn middleware_fn<S, T, E>(service: &S, ctx: WebContext<'_>) -> Result<T, E>
251//! where
252//!     S: for<'r> Service<WebContext<'r>, Response = T, Error = E>
253//! {
254//!     service.call(ctx).await
255//! }
256//! ```
257//! For more detailed middleware documentation please reference [middleware]
258//!
259//! ## Cross crates integration
260//! use tower-http inside xitca-web application.
261//! ```rust
262//! # #[cfg(feature = "tower-http-compat")]
263//! # fn _main() -> std::io::Result<()> {
264//! use tower_http::services::ServeDir;
265//! use xitca_web::{
266//!     service::tower_http_compat::TowerHttpCompat,
267//!     App
268//! };
269//!
270//! App::new()
271//!     .at("/", TowerHttpCompat::new(ServeDir::new("/some_folder")))
272//!     .serve()
273//!     .bind("localhost:8080")?
274//!     .run()
275//!     .wait()
276//! # }
277//! ```
278//!
279//! # Fast compile time
280//! - additive proc macro
281//! - light weight dependency tree
282//!
283//! ## opt-in proc macro
284//! in xitca-web proc macro is opt-in. This result in a fast compile time with zero
285//! public proc macro. That said you still can enable macros for a higher level style
286//! of API.
287//! ```rust
288//! # #[cfg(feature = "codegen")]
289//! # async fn _main() -> std::io::Result<()> {
290//! use xitca_web::{codegen::route, App};
291//!
292//! #[route("/", method = get)]
293//! async fn index() -> &'static str {
294//!     "Hello,World!"
295//! }
296//!
297//! App::new()
298//!     .at_typed(index)
299//!     .serve()
300//!     .bind("localhost:8080")?
301//!     .run()
302//!     .await
303//! # }
304//! ```
305
306#![forbid(unsafe_code)]
307#![cfg_attr(feature = "nightly", feature(async_iterator, error_generic_member_access))]
308
309mod app;
310mod context;
311#[cfg(feature = "__server")]
312mod server;
313
314pub mod body;
315pub mod error;
316pub mod handler;
317pub mod middleware;
318pub mod service;
319pub mod test;
320
321#[cfg(feature = "codegen")]
322pub mod codegen {
323    //! macro code generation module.
324
325    /// Derive macro for individual struct field type extractable through [StateRef](crate::handler::state::StateRef)
326    /// and [StateOwn](crate::handler::state::StateOwn)
327    ///
328    /// # Example:
329    /// ```rust
330    /// # use xitca_web::{codegen::State, handler::{handler_service, state::StateRef}, App, WebContext};
331    ///
332    /// // use derive macro and attribute to mark the field that can be extracted.
333    /// #[derive(State, Clone)]
334    /// struct MyState {
335    ///     #[borrow]
336    ///     field: u128
337    /// }
338    ///
339    /// # async fn app() {
340    /// // construct App with MyState type.
341    /// App::new()
342    ///     .with_state(MyState { field: 996 })
343    ///     .at("/", handler_service(index))
344    /// #   .at("/nah", handler_service(nah));
345    /// # }
346    ///
347    /// // extract u128 typed field from MyState.
348    /// async fn index(StateRef(num): StateRef<'_, u128>) -> String {
349    ///     assert_eq!(*num, 996);
350    ///     num.to_string()
351    /// }
352    /// # async fn nah(_: &WebContext<'_, MyState>) -> &'static str {
353    /// #   // needed to infer the body type of request
354    /// #   ""
355    /// # }
356    /// ```
357    pub use xitca_codegen::State;
358
359    pub use xitca_codegen::route;
360
361    pub use xitca_codegen::error_impl;
362
363    #[doc(hidden)]
364    /// a hidden module for macro to access public types that are not framework user facing.
365    pub mod __private {
366        pub use xitca_http::util::service::router::{IntoObject, RouteObject, RouterMapErr, TypedRoute};
367    }
368}
369
370pub mod http {
371    //! http types
372
373    use super::body::{RequestBody, ResponseBody};
374
375    pub use xitca_http::http::*;
376
377    /// type alias for default request type xitca-web uses.
378    pub type WebRequest<B = RequestBody> = Request<RequestExt<B>>;
379
380    /// type alias for default response type xitca-web uses.
381    pub type WebResponse<B = ResponseBody> = Response<B>;
382}
383
384pub mod route {
385    //! route services.
386    //! # Examples:
387    //! ```
388    //! # use xitca_web::{
389    //! #   handler::handler_service,
390    //! #   http::Method,
391    //! #   route::{get, post, put, Route}
392    //! # };
393    //! # fn _route() -> Result<(), Box<dyn std::error::Error>> {
394    //! // a simple async function service.
395    //! let service = handler_service(|_: ()| async { });
396    //!
397    //! let custom_method = Method::from_bytes(b"huh")?;
398    //!
399    //! // route get http method and a user custom method to handler_service
400    //! Route::new([Method::GET, custom_method]).route(service.clone());
401    //!
402    //! // shortcut for single http method route(s). they can chained multiple times.
403    //! get(service.clone()).post(service.clone()).put(service);
404    //! # Ok(())
405    //! # }
406    //! ```
407    pub use xitca_http::util::service::route::{Route, connect, delete, get, head, options, patch, post, put, trace};
408}
409
410pub use app::{App, AppObject, NestApp};
411pub use body::BodyStream;
412pub use context::WebContext;
413#[cfg(feature = "__server")]
414pub use server::HttpServer;
415
416pub use xitca_http::bytes;