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