diff --git a/src/app.rs b/src/app.rs index fcb491a2199..72cd9f9735d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -71,16 +71,38 @@ where InitError = (), >, { - /// Set application data. Application data could be accessed - /// by using `Data` extractor where `T` is data type. + /// Adds an arbitrary application level data item. /// - /// **Note**: http server accepts an application factory rather than - /// an application instance. Http server constructs an application - /// instance for each thread, thus application data must be constructed - /// multiple times. If you want to share data between different - /// threads, a shared object should be used, e.g. `Arc`. Internally `Data` type - /// uses `Arc` so data could be created outside of app factory and clones could - /// be stored via `App::app_data()` method. + /// Application data can be accessed by using a `Data` extractor where `T` is the data type. + /// + /// The state is managed on a per-type basis and as such there can be + /// at most one value for any given type. + /// This means that only the first invocation of this function per type will have an effect, + /// all later ones will be ignored. + /// + /// Internally the data will be wrapped in an `Arc`. + /// If your data is already wrapped in an `Arc` + /// you can instead store it directly using the `App::app_data()` function. + /// Note: There is a `From>` implementation for `Data` so anything wrapped in an `Arc` + /// can be converted to a `Data` like this: + /// + /// ```rust + /// use std::sync::Arc; + /// use actix_web::web::Data; + /// + /// let arc = Arc::new(String::from("test-123")); + /// let data_from_arc = Data::from(arc); + /// ``` + /// + /// **Note**: `HttpServer` accepts an application factory (closure) rather than + /// an application instance (`App`). + /// `HttpServer` constructs an application instance for each thread + /// by calling this factory closure thus application data must be constructed multiple times. + /// If you want to share data between different threads, + /// a shared object should be used, e.g. `Arc`. + /// + /// If route data is not set for a handler, using `Data` extractor would cause an *Internal + /// Server Error* response. /// /// ```rust /// use std::cell::Cell; @@ -137,13 +159,60 @@ where self } - /// Set application level arbitrary data item. + /// Adds an arbirtraty application level data item. + /// + /// This data is available to all routes and can be added during the application. + /// There are two ways to retrieve this data: + /// + /// 1. At runtime via the `HttpRequest::app_data()` method + /// 2. If data of type `T` is stored wrapped in a `Data` object + /// it can also be retrieved using a `Data` extractor /// - /// Application data stored with `App::app_data()` method is available - /// via `HttpRequest::app_data()` method at runtime. + /// The state is managed on a per-type basis and as such there can be + /// at most one value for any given type. + /// Later invocations overwrite earlier ones. + /// This means that only the last invocation of this function per type will have an effect. + /// + /// **Note**: `HttpServer` accepts an application factory (closure) rather than + /// an application instance (`App`). + /// `HttpServer` constructs an application instance for each thread + /// by calling this factory closure thus application data must be constructed multiple times. + /// If you want to share data between different threads, + /// a shared object should be used, e.g. `Arc`. + /// + /// ```rust + /// use std::sync::Mutex; + /// use actix_web::{web, App, HttpResponse, HttpRequest, Responder}; /// - /// This method could be used for storing `Data` as well, in that case - /// data could be accessed by using `Data` extractor. + /// struct MyData { + /// counter: usize, + /// } + /// + /// /// Use the `Data` extractor to access data in a handler. + /// async fn index(data: web::Data>) -> impl Responder { + /// let mut data = data.lock().unwrap(); + /// data.counter += 1; + /// HttpResponse::Ok().body(format!("{}", data.counter)) + /// } + /// + /// async fn hello(req: HttpRequest) -> impl Responder { + /// let data = req.app_data::>>(); + /// let mut data = data.unwrap().lock().unwrap(); + /// data.counter += 1; + /// HttpResponse::Ok().body(format!("{}", data.counter)) + ///} + /// + /// fn main() { + /// let data = web::Data::new(Mutex::new(MyData{ counter: 0 })); + /// + /// let app = App::new() + /// // Store `MyData` in application storage. + /// .app_data(data) + /// .service( + /// web::resource("/index.html").route( + /// web::get().to(index))); + /// } + /// ``` pub fn app_data(mut self, ext: U) -> Self { self.extensions.insert(ext); self diff --git a/src/data.rs b/src/data.rs index 19c258ff06e..dbb5b9f25dc 100644 --- a/src/data.rs +++ b/src/data.rs @@ -18,49 +18,11 @@ pub(crate) trait DataFactory { pub(crate) type FnDataFactory = Box LocalBoxFuture<'static, Result, ()>>>; -/// Application data. +/// Wrapper for a piece of data. /// -/// Application level data is a piece of arbitrary data attached to the app, scope, or resource. -/// Application data is available to all routes and can be added during the application -/// configuration process via `App::data()`. +/// Internally it wraps the data in an `Arc`. /// -/// Application data can be accessed by using `Data` extractor where `T` is data type. -/// -/// **Note**: http server accepts an application factory rather than an application instance. HTTP -/// server constructs an application instance for each thread, thus application data must be -/// constructed multiple times. If you want to share data between different threads, a shareable -/// object should be used, e.g. `Send + Sync`. Application data does not need to be `Send` -/// or `Sync`. Internally `Data` uses `Arc`. -/// -/// If route data is not set for a handler, using `Data` extractor would cause *Internal -/// Server Error* response. -/// -/// ```rust -/// use std::sync::Mutex; -/// use actix_web::{web, App, HttpResponse, Responder}; -/// -/// struct MyData { -/// counter: usize, -/// } -/// -/// /// Use the `Data` extractor to access data in a handler. -/// async fn index(data: web::Data>) -> impl Responder { -/// let mut data = data.lock().unwrap(); -/// data.counter += 1; -/// HttpResponse::Ok() -/// } -/// -/// fn main() { -/// let data = web::Data::new(Mutex::new(MyData{ counter: 0 })); -/// -/// let app = App::new() -/// // Store `MyData` in application storage. -/// .app_data(data.clone()) -/// .service( -/// web::resource("/index.html").route( -/// web::get().to(index))); -/// } -/// ``` +/// See [`App::data()`] and [`App::app_data()`] for when and how to use this. #[derive(Debug)] pub struct Data(Arc);