Skip to main content

App

Struct App 

Source
pub struct App { /* private fields */ }
Expand description

The built-in HTTP application. Serves static files, favicons, forms, file uploads, health probes, metrics, and a 404 fallback.

Use as-is or compose with the framework’s building blocks:

use rust_web_server::app::App;
use rust_web_server::middleware::{WithMiddleware, RateLimitLayer};
use rust_web_server::core::New;

// Middleware stack around the built-in app
let app = App::new().wrap(RateLimitLayer);

For user-defined routes with shared state, call App::with_state:

use rust_web_server::app::App;
use rust_web_server::response::{Response, STATUS_CODE_REASON_PHRASE};
use rust_web_server::core::New;

struct State { version: &'static str }

let app = App::with_state(State { version: "1.0" })
    .get("/version", |_req, _params, _conn, state| {
        let mut r = Response::new();
        r.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
        r.reason_phrase = STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
        r
    });

§Per-instance configuration

By default App::new() reads CORS, CSP, and other settings from environment variables on each request (matching the current process state, including hot-reloaded values). Call App::with_config to pin the configuration to a specific ServerConfig — this is the recommended pattern for parallel integration tests, which should not touch environment variables at all.

use rust_web_server::app::App;
use rust_web_server::server_config::ServerConfig;
use rust_web_server::test_client::TestClient;

// No env writes, no lock needed — safe to run in parallel.
let app = App::with_config(ServerConfig {
    cors_allow_all: false,
    cors_allow_origins: "https://trusted.example.com".to_string(),
    ..ServerConfig::default()
});
let client = TestClient::new(app);

Implementations§

Source§

impl App

Source

pub fn with_config(config: ServerConfig) -> Self

Create an App pinned to an explicit ServerConfig.

All CORS, CSP, and other header settings are taken from config rather than from environment variables. The configuration is fixed for the lifetime of the App instance — SIGHUP / hot-reload do not affect it.

This is the preferred constructor for integration tests: build a ServerConfig with the exact settings under test, pass it here, and use TestClient to drive requests. No environment writes and no test_env::lock() are needed.

Source§

impl App

Source

pub fn handle_request(request: Request) -> (Response, Request)

Dispatch request through the controller chain and return the response.

This is a convenience wrapper over Application::execute that uses a synthetic loopback ConnectionInfo. Use it in tests or when no real connection context is available. Prefer TestClient for structured test code.

Source

pub fn with_state<S: Send + Sync + 'static>(state: S) -> AppWithState<S>

Create a state-aware application. Routes registered on the returned AppWithState<S> are tried first; unmatched requests fall through to the built-in controller chain (static files, health probes, etc.).

The state is stored as Arc<S> and shared across all handlers.

§Example
use rust_web_server::app::App;
use rust_web_server::response::{Response, STATUS_CODE_REASON_PHRASE};
use rust_web_server::core::New;

struct Db { url: String }

let app = App::with_state(Db { url: "postgres://...".to_string() })
    .get("/ping", |_req, _params, _conn, db| {
        let mut r = Response::new();
        r.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
        r.reason_phrase = STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
        r
    });
Source

pub fn wrap<M: Middleware + 'static>(self, layer: M) -> WithMiddleware<App>

Wrap this application in a middleware layer.

Returns a WithMiddleware<App> that runs layer before every request. Chain .wrap() calls to stack multiple layers:

use rust_web_server::app::App;
use rust_web_server::middleware::RateLimitLayer;
use rust_web_server::core::New;

let app = App::new().wrap(RateLimitLayer);
Source

pub fn mcp( self, name: impl Into<String>, version: impl Into<String>, ) -> McpServer

Attach an MCP server to this application. Tools, resources, and prompts are registered on the returned McpServer; requests that do not match the MCP endpoint are forwarded to self (static files, health probes, any custom routes registered before this call).

use rust_web_server::app::App;
use rust_web_server::mcp::{McpContent, extract_arg};
use rust_web_server::core::New;

// Pure MCP — unmatched paths handled by built-in App
let app = App::new()
    .mcp("my-server", "1.0")
    .tool(
        "echo",
        "Echo text back",
        r#"{"type":"object","properties":{"text":{"type":"string"}}}"#,
        |args| Ok(McpContent::text(extract_arg(args, "text").unwrap_or_default())),
    );

To combine with custom HTTP routes, start from App::with_state:

use rust_web_server::app::App;
use rust_web_server::mcp::McpContent;
use rust_web_server::response::{Response, STATUS_CODE_REASON_PHRASE};
use rust_web_server::core::New;

let app = App::with_state(())
    .get("/api/ping", |_, _, _, _| {
        let mut r = Response::new();
        r.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
        r.reason_phrase = STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
        r
    })
    .mcp("my-server", "1.0")
    .tool("ping", "Ping the server", "{}", |_| Ok(McpContent::text("pong")));
Source

pub fn with_async_state<S: Send + Sync + 'static>( state: S, ) -> AsyncAppWithState<S>

Create an async state-aware application (requires the http2 feature).

Handlers are async fn closures that can await database queries, HTTP clients, or any other async I/O. Unmatched routes fall through to the built-in controller chain.

§Example
use std::sync::Arc;
use rust_web_server::app::App;
use rust_web_server::response::{Response, STATUS_CODE_REASON_PHRASE};
use rust_web_server::core::New;

struct Db { url: String }

let app = App::with_async_state(Db { url: "postgres://...".to_string() })
    .get("/ping", |_req, _params, _conn, state| async move {
        // state: Arc<Db>
        let mut r = Response::new();
        r.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
        r.reason_phrase = STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
        r
    });

Trait Implementations§

Source§

impl Application for App

Source§

fn execute( &self, request: &Request, connection: &ConnectionInfo, ) -> Result<Response, String>

Receives a parsed request and returns a fully-built response. Walk your controller list with is_matching / process and return the first match.
Source§

impl Clone for App

Source§

fn clone(&self) -> App

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl New for App

Source§

fn new() -> Self

Auto Trait Implementations§

§

impl Freeze for App

§

impl RefUnwindSafe for App

§

impl Send for App

§

impl Sync for App

§

impl Unpin for App

§

impl UnsafeUnpin for App

§

impl UnwindSafe for App

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more