boluo/
lib.rs

1//! `boluo` 是一个简单易用的异步网络框架。
2//!
3//! # 目录
4//!
5//! - [快速开始](#快速开始)
6//! - [服务](#服务)
7//! - [处理程序](#处理程序)
8//! - [提取器](#提取器)
9//! - [响应](#响应)
10//! - [路由](#路由)
11//! - [错误处理](#错误处理)
12//! - [中间件](#中间件)
13//!
14//! # 快速开始
15//!
16//! 新建项目:
17//!
18//! ```bash
19//! cargo new demo && cd demo
20//! ```
21//!
22//! 添加依赖:
23//!
24//! ```toml
25//! [dependencies]
26//! boluo = "0.7"
27//! tokio = { version = "1", features = ["full"] }
28//! ```
29//!
30//! 用以下内容覆盖 `src/main.rs`:
31//!
32//! ```no_run
33//! use boluo::response::IntoResponse;
34//! use boluo::route::Router;
35//! use boluo::server::Server;
36//! use tokio::net::TcpListener;
37//!
38//! #[tokio::main]
39//! async fn main() {
40//!     let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
41//!
42//!     let app = Router::new().mount(hello);
43//!
44//!     Server::new(listener).run(app).await.unwrap();
45//! }
46//!
47//! #[boluo::route("/", method = "GET")]
48//! async fn hello() -> impl IntoResponse {
49//!     "Hello, World!"
50//! }
51//! ```
52//!
53//! 运行项目:
54//!
55//! ```bash
56//! cargo run
57//! ```
58//!
59//! 访问服务:
60//!
61//! ```bash
62//! curl http://127.0.0.1:3000/
63//! ```
64//!
65//! # 服务
66//!
67//! [`Service`] 特征表示一个接收请求并返回响应的异步函数。
68//!
69//! # 处理程序
70//!
71//! 处理程序是一个异步函数,它接受零个或多个提取器作为参数,并返回可以转换为响应的内容。
72//!
73//! 处理程序如下所示:
74//!
75//! ```
76//! use boluo::body::Body;
77//! use boluo::handler::handler_fn;
78//! use boluo::response::IntoResponse;
79//!
80//! // 返回空的 `200 OK` 响应的处理程序。
81//! async fn empty() {}
82//!
83//! // 返回带有纯文本主体的 `200 OK` 响应的处理程序。
84//! async fn hello() -> &'static str {
85//!     "Hello, World!"
86//! }
87//!
88//! // 返回带有请求主体的 `200 OK` 响应的处理程序。
89//! //
90//! // `Body` 实现了 `FromRequest` 特征,可以作为提取器解析请求。并且也实现了
91//! // `IntoResponse` 特征,可以作为响应类型。
92//! async fn echo(body: Body) -> impl IntoResponse {
93//!     body
94//! }
95//!
96//! // 使用 `handler_fn` 函数将处理程序转换为 `Service`。
97//! let service = handler_fn(echo);
98//! ```
99//!
100//! # 提取器
101//!
102//! 提取器是实现了 [`FromRequest`] 特征的类型,可以根据 [`Request`] 创建实例。
103//!
104//! ```
105//! use std::convert::Infallible;
106//!
107//! use boluo::extract::FromRequest;
108//! use boluo::http::{header, HeaderValue};
109//! use boluo::request::Request;
110//!
111//! // 从请求头中提取 HOST 的提取器。
112//! struct Host(Option<HeaderValue>);
113//!
114//! // 为提取器实现 `FromRequest` 特征。
115//! impl FromRequest for Host {
116//!     type Error = Infallible;
117//!
118//!     async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
119//!         let value = req.headers().get(header::HOST).map(|v| v.to_owned());
120//!         Ok(Host(value))
121//!     }
122//! }
123//!
124//! // 在处理程序中使用提取器从请求中提取数据。
125//! async fn using_extractor(Host(host): Host) {
126//!     println!("{host:?}")
127//! }
128//! ```
129//!
130//! # 响应
131//!
132//! 任何实现 [`IntoResponse`] 特征的类型都可以作为响应。
133//!
134//! ```
135//! use boluo::response::Html;
136//! use boluo::response::IntoResponse;
137//!
138//! // 返回带有纯文本主体的 `200 OK` 响应的处理程序。
139//! async fn hello() -> &'static str {
140//!     "Hello, World!"
141//! }
142//!
143//! // 返回显示 `Hello, World!` 的 HTML 页面的处理程序。
144//! async fn html() -> impl IntoResponse {
145//!     Html("<html><body>Hello, World!</body></html>")
146//! }
147//! ```
148//!
149//! # 路由
150//!
151//! [`Router`] 用于设置哪些路径通向哪些服务。
152//!
153//! ```
154//! use boluo::handler::handler_fn;
155//! use boluo::route::Router;
156//!
157//! #[boluo::route("/f", method = "GET")]
158//! async fn f() -> &'static str {
159//!     "f"
160//! }
161//!
162//! let ab = Router::new()
163//!     .route("/a", handler_fn(|| async { "a" }))
164//!     .route("/b", handler_fn(|| async { "b" }));
165//!
166//! let cd = Router::new()
167//!     .route("/c", handler_fn(|| async { "c" }))
168//!     .route("/d", handler_fn(|| async { "d" }));
169//!
170//! Router::new()
171//!     // 路由。
172//!     .route("/a", handler_fn(|| async { "a" }))
173//!     .route("/b", handler_fn(|| async { "b" }))
174//!     // 嵌套路由。
175//!     .scope("/x", ab)
176//!     // 将其他路由器的路由合并到当前路由器。
177//!     .merge(cd)
178//!     // 挂载宏定义路由。
179//!     .mount(f);
180//! ```
181//!
182//! # 错误处理
183//!
184//! 错误和响应是分离的,可以在中间件对特定错误进行捕获,并将错误转换为自己想要的响应格式。
185//!
186//! 未经处理的错误到达服务器时,服务器将返回带有错误信息的 `500 INTERNAL_SERVER_ERROR` 响应。
187//!
188//! ```
189//! use boluo::http::StatusCode;
190//! use boluo::response::{IntoResponse, Response};
191//! use boluo::route::{RouteError, RouteErrorKind, Router};
192//! use boluo::service::ServiceExt;
193//! use boluo::BoxError;
194//!
195//! #[derive(Debug)]
196//! struct MyError;
197//!
198//! impl std::fmt::Display for MyError {
199//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200//!         write!(f, "some error message")
201//!     }
202//! }
203//!
204//! impl std::error::Error for MyError {}
205//!
206//! // 处理程序。
207//! #[boluo::route("/", method = "GET")]
208//! async fn throw_error() -> Result<(), MyError> {
209//!     Err(MyError)
210//! }
211//!
212//! // 错误处理。
213//! async fn handle_error(err: BoxError) -> Result<Response, BoxError> {
214//!     // 处理框架抛出的路由错误,并自定义响应方式。
215//!     if let Some(e) = err.downcast_ref::<RouteError>() {
216//!         let status_code = match e.kind() {
217//!             RouteErrorKind::NotFound => StatusCode::NOT_FOUND,
218//!             RouteErrorKind::MethodNotAllowed => StatusCode::METHOD_NOT_ALLOWED,
219//!         };
220//!         return Ok((status_code, format!("{status_code}")).into_response()?);
221//!     }
222//!     if let Some(_) = err.downcast_ref::<MyError>() {
223//!         // 记录错误、转为响应等等。
224//!     }
225//!     Err(err)
226//! }
227//!
228//! Router::new().mount(throw_error).or_else(handle_error);
229//! ```
230//!
231//! # 中间件
232//!
233//! 中间件是实现了 [`Middleware`] 特征的类型,可以调用 [`ServiceExt::with`] 函数将中间件
234//! 应用于 [`Service`]。
235//!
236//! 中间件实际上是将原始服务转换为新的服务。
237//!
238//! ```
239//! use boluo::data::Extension;
240//! use boluo::handler::handler_fn;
241//! use boluo::service::ServiceExt;
242//!
243//! async fn extension(Extension(text): Extension<&'static str>) -> &'static str {
244//!     text
245//! }
246//!
247//! let service = handler_fn(extension);
248//! let service = service.with(Extension("Hello, World!"));
249//! ```
250//!
251//! [`Service`]: crate::service::Service
252//! [`FromRequest`]: crate::extract::FromRequest
253//! [`Request`]: crate::request::Request
254//! [`IntoResponse`]: crate::response::IntoResponse
255//! [`Router`]: crate::route::Router
256//! [`Middleware`]: crate::middleware::Middleware
257//! [`ServiceExt::with`]: crate::service::ServiceExt::with
258
259#![forbid(unsafe_code)]
260#![warn(
261    missing_debug_implementations,
262    missing_docs,
263    rust_2018_idioms,
264    unreachable_pub
265)]
266#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))]
267
268pub use boluo_core::BoxError;
269pub use boluo_core::{body, handler, http, request, service, upgrade};
270
271pub use boluo_macros::route;
272
273pub mod data;
274pub mod extract;
275pub mod listener;
276pub mod middleware;
277pub mod response;
278pub mod route;
279
280pub use headers;
281
282#[cfg(any(feature = "http1", feature = "http2"))]
283pub mod server;
284
285#[cfg(feature = "multipart")]
286pub mod multipart;
287
288#[cfg(feature = "ws")]
289pub mod ws;
290
291#[cfg(feature = "static-file")]
292pub mod static_file;