From ad3d3a70c488380e54d6cbd85049e7ded44c227e Mon Sep 17 00:00:00 2001 From: Lars Francke Date: Tue, 27 Oct 2020 15:19:25 +0100 Subject: [PATCH] Second stab at improving the data/app_data documentation. --- src/app.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++------- src/data.rs | 44 +++------------------------------- 2 files changed, 63 insertions(+), 50 deletions(-) diff --git a/src/app.rs b/src/app.rs index 8865bf457..68069c5df 100644 --- a/src/app.rs +++ b/src/app.rs @@ -70,7 +70,8 @@ where InitError = (), >, { - /// Adds application data. + /// Adds an arbirtraty application level data item. + /// /// 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 @@ -82,13 +83,16 @@ where /// If your data is already wrapped in an `Arc` /// you can instead store it directly using the `App::app_data()` function. /// - /// **Note**: `HttpServer` accepts an application factory rather than + /// **Note**: `HttpServer` accepts an application factory (closure) rather than /// an application instance (`App`). - /// `HttpServer` constructs an application instance for each thread, - /// thus application data must be constructed multiple times. + /// `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; /// use actix_web::{web, App, HttpResponse, Responder}; @@ -144,13 +148,60 @@ where self } - /// Set application level arbitrary data item. + /// Adds an arbirtraty application level data item. /// - /// Application data stored with `App::app_data()` method is available - /// via `HttpRequest::app_data()` method at runtime. + /// This data is available to all routes and can be added during the application. + /// There are two ways to retrieve this data: /// - /// This method could be used for storing `Data` as well, in that case - /// data could be accessed by using `Data` extractor. + /// 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 + /// + /// 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}; + /// + /// 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 19c258ff0..1738ae90f 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);