actix_web/web.rs
1//! Essentials helper functions and types for application registration.
2//!
3//! # Request Extractors
4//! - [`Data`]: Application data item
5//! - [`ThinData`]: Cheap-to-clone application data item
6//! - [`ReqData`]: Request-local data item
7//! - [`Path`]: URL path parameters / dynamic segments
8//! - [`Query`]: URL query parameters
9//! - [`Header`]: Typed header
10//! - [`Json`]: JSON payload
11//! - [`Form`]: URL-encoded payload
12//! - [`Bytes`]: Raw payload
13//!
14//! # Responders
15//! - [`Json`]: JSON response
16//! - [`Form`]: URL-encoded response
17//! - [`Bytes`]: Raw bytes response
18//! - [`Redirect`](Redirect::to): Convenient redirect responses
19
20use std::{borrow::Cow, future::Future};
21
22use actix_router::IntoPatterns;
23pub use bytes::{Buf, BufMut, Bytes, BytesMut};
24use tokio::task::spawn_blocking;
25
26pub use crate::{
27 config::ServiceConfig, data::Data, redirect::Redirect, request_data::ReqData,
28 thin_data::ThinData, types::*,
29};
30use crate::{
31 error::BlockingError, http::Method, service::WebService, FromRequest, Handler, Resource,
32 Responder, Route, Scope,
33};
34
35/// Creates a new resource for a specific path.
36///
37/// Resources may have dynamic path segments. For example, a resource with the path `/a/{name}/c`
38/// would match all incoming requests with paths such as `/a/b/c`, `/a/1/c`, or `/a/etc/c`.
39///
40/// A dynamic segment is specified in the form `{identifier}`, where the identifier can be used
41/// later in a request handler to access the matched value for that segment. This is done by looking
42/// up the identifier in the `Path` object returned by [`HttpRequest::match_info()`](crate::HttpRequest::match_info) method.
43///
44/// By default, each segment matches the regular expression `[^{}/]+`.
45///
46/// You can also specify a custom regex in the form `{identifier:regex}`:
47///
48/// For instance, to route `GET`-requests on any route matching `/users/{userid}/{friend}` and store
49/// `userid` and `friend` in the exposed `Path` object:
50///
51/// # Examples
52/// ```
53/// use actix_web::{web, App, HttpResponse};
54///
55/// let app = App::new().service(
56/// web::resource("/users/{userid}/{friend}")
57/// .route(web::get().to(|| HttpResponse::Ok()))
58/// .route(web::head().to(|| HttpResponse::MethodNotAllowed()))
59/// );
60/// ```
61pub fn resource<T: IntoPatterns>(path: T) -> Resource {
62 Resource::new(path)
63}
64
65/// Creates scope for common path prefix.
66///
67/// Scopes collect multiple paths under a common path prefix. The scope's path can contain dynamic
68/// path segments.
69///
70/// # Avoid Trailing Slashes
71/// Avoid using trailing slashes in the scope prefix (e.g., `web::scope("/scope/")`). It will almost
72/// certainly not have the expected behavior. See the [documentation on resource definitions][pat]
73/// to understand why this is the case and how to correctly construct scope/prefix definitions.
74///
75/// # Examples
76/// In this example, three routes are set up (and will handle any method):
77/// - `/{project_id}/path1`
78/// - `/{project_id}/path2`
79/// - `/{project_id}/path3`
80///
81/// # Examples
82/// ```
83/// use actix_web::{web, App, HttpResponse};
84///
85/// let app = App::new().service(
86/// web::scope("/{project_id}")
87/// .service(web::resource("/path1").to(|| HttpResponse::Ok()))
88/// .service(web::resource("/path2").to(|| HttpResponse::Ok()))
89/// .service(web::resource("/path3").to(|| HttpResponse::MethodNotAllowed()))
90/// );
91/// ```
92///
93/// [pat]: crate::dev::ResourceDef#prefix-resources
94pub fn scope(path: &str) -> Scope {
95 Scope::new(path)
96}
97
98/// Creates a new un-configured route.
99pub fn route() -> Route {
100 Route::new()
101}
102
103macro_rules! method_route {
104 ($method_fn:ident, $method_const:ident) => {
105 #[doc = concat!(" Creates a new route with `", stringify!($method_const), "` method guard.")]
106 ///
107 /// # Examples
108 #[doc = concat!(" In this example, one `", stringify!($method_const), " /{project_id}` route is set up:")]
109 /// ```
110 /// use actix_web::{web, App, HttpResponse};
111 ///
112 /// let app = App::new().service(
113 /// web::resource("/{project_id}")
114 #[doc = concat!(" .route(web::", stringify!($method_fn), "().to(|| HttpResponse::Ok()))")]
115 ///
116 /// );
117 /// ```
118 pub fn $method_fn() -> Route {
119 method(Method::$method_const)
120 }
121 };
122}
123
124method_route!(get, GET);
125method_route!(post, POST);
126method_route!(put, PUT);
127method_route!(patch, PATCH);
128method_route!(delete, DELETE);
129method_route!(head, HEAD);
130method_route!(trace, TRACE);
131
132/// Creates a new route with specified method guard.
133///
134/// # Examples
135/// In this example, one `GET /{project_id}` route is set up:
136///
137/// ```
138/// use actix_web::{web, http, App, HttpResponse};
139///
140/// let app = App::new().service(
141/// web::resource("/{project_id}")
142/// .route(web::method(http::Method::GET).to(|| HttpResponse::Ok()))
143/// );
144/// ```
145pub fn method(method: Method) -> Route {
146 Route::new().method(method)
147}
148
149/// Creates a new any-method route with handler.
150///
151/// ```
152/// use actix_web::{web, App, HttpResponse, Responder};
153///
154/// async fn index() -> impl Responder {
155/// HttpResponse::Ok()
156/// }
157///
158/// App::new().service(
159/// web::resource("/").route(
160/// web::to(index))
161/// );
162/// ```
163pub fn to<F, Args>(handler: F) -> Route
164where
165 F: Handler<Args>,
166 Args: FromRequest + 'static,
167 F::Output: Responder + 'static,
168{
169 Route::new().to(handler)
170}
171
172/// Creates a raw service for a specific path.
173///
174/// ```
175/// use actix_web::{dev, web, guard, App, Error, HttpResponse};
176///
177/// async fn my_service(req: dev::ServiceRequest) -> Result<dev::ServiceResponse, Error> {
178/// Ok(req.into_response(HttpResponse::Ok().finish()))
179/// }
180///
181/// let app = App::new().service(
182/// web::service("/users/*")
183/// .guard(guard::Header("content-type", "text/plain"))
184/// .finish(my_service)
185/// );
186/// ```
187pub fn service<T: IntoPatterns>(path: T) -> WebService {
188 WebService::new(path)
189}
190
191/// Create a relative or absolute redirect.
192///
193/// See [`Redirect`] docs for usage details.
194///
195/// # Examples
196/// ```
197/// use actix_web::{web, App};
198///
199/// let app = App::new()
200/// // the client will resolve this redirect to /api/to-path
201/// .service(web::redirect("/api/from-path", "to-path"));
202/// ```
203pub fn redirect(from: impl Into<Cow<'static, str>>, to: impl Into<Cow<'static, str>>) -> Redirect {
204 Redirect::new(from, to)
205}
206
207/// Executes blocking function on a thread pool, returns future that resolves to result of the
208/// function execution.
209pub fn block<F, R>(f: F) -> impl Future<Output = Result<R, BlockingError>>
210where
211 F: FnOnce() -> R + Send + 'static,
212 R: Send + 'static,
213{
214 let fut = spawn_blocking(f);
215 async { fut.await.map_err(|_| BlockingError) }
216}