Application state holds data that describes an application’s current condition. In a REST service, that includes resource data: adding or removing a course changes the service’s state. State can also hold shared dependencies, such as a database connection pool. The course service first keeps its resources in memory, then moves them to Postgres. section 3.2.2 section 4.3.2
An Actix server runs application instances on multiple worker threads; their data is not shared automatically. Define an `AppState` in `state.rs`, construct it once with `web::Data::new(...)`, and attach clones of that shared data to the app with `.app_data(shared_data.clone())`. A handler receives it as a `web::Data<AppState>` parameter. section 3.2.2
Start with a health check
Give `AppState` a `health_check_response: String` and `visit_count: Mutex<u32>`. The `/health` handler reads the string, locks the count, includes its current value in the response, and increments it. The string illustrates shared immutable data; the mutex protects a value that requests mutate. section 3.2.2
Listing 3.3 Building an Actix web server with application state
use actix_web::{web, App, HttpServer};
use std::io;
use std::sync::Mutex;
#[path = "../handlers.rs"]
mod handlers;
#[path = "../routes.rs"]
mod routes;
#[path = "../state.rs"]
mod state;
use routes::*;
use state::AppState;
#[actix_rt::main]
async fn main() -> io::Result<()> {
let shared_data = web::Data::new(AppState { #1
health_check_response: "I'm good. You've already asked me ".to_string(),
visit_count: Mutex::new(0),
});
let app = move || { #2
App::new()
.app_data(shared_data.clone()) #3
.configure(general_routes) #4
};
HttpServer::new(app).bind("127.0.0.1:3000")?.run().await #5
}
Shows where the state is initialized and attached to the Actix application. section 3.2.2
For the in-memory course API, add `courses: Mutex<Vec<Course>>` to `AppState` and initialize it with an empty vector in `bin/tutor-service.rs`. Keep the `Course` data model in `models.rs`, route definitions in `routes.rs`, and request logic in `handlers.rs`. This version uses the shared collection instead of a persistent data store. section 3.2.1 section 3.2.3
The course handlers put that state to work:
- A POST to `/courses/` supplies JSON course data. The handler receives `AppState`, counts existing courses for that tutor, creates the new course, and stores it in the shared collection. section 3.2.4
- A GET to `/courses/{tutor_id}` reads the collection, filters it by the path parameter, and returns the matching courses as JSON. section 3.2.5
When courses move to Postgres, change what state carries: retain the health-check fields, but replace the in-memory course collection with `db: PgPool`. In `main()`, read `DATABASE_URL`, create the sqlx pool, place it in `AppState`, and inject the state into Actix. A course handler extracts `app_state.db`, passes the pool and request parameters to a database-access function, and turns its result into an HTTP response. Resource data now lives in the database; state supplies the shared means of accessing it. section 4.3.2 section 4.3.3 section 4.4.2
use sqlx::postgres::PgPool;
use std::sync::Mutex;
pub struct AppState {
pub health_check_response: String,
pub visit_count: Mutex<u32>,
pub db: PgPool,
}
Shows the database-backed `AppState` fields after the in-memory course collection is replaced by a Postgres pool. section 4.3.2
Tests can call handlers directly by constructing `web::Data<AppState>` and the required request arguments themselves. Initialize an empty course collection for an in-memory test, or create a test pool for a database-backed one. Check more than an unconditional success response when testing real state changes: skeletal handlers can pass status-code tests before database access exists. section 3.2.4 section 4.3.4






































