pub struct App { /* private fields */ }Expand description
Primary entry point for building an Oxide application.
Uses a builder pattern to configure routes, state, middleware, and then start the server.
§Example
use oxide_framework_core::{App, ApiResponse, Config};
use serde::Serialize;
#[derive(Serialize)]
struct Msg { text: String }
async fn index(Config(cfg): Config) -> ApiResponse<Msg> {
ApiResponse::ok(Msg { text: format!("Hello from {}!", cfg.app_name) })
}
fn main() {
App::new()
.config("app.yaml")
.rate_limit(100, 60)
.cors_permissive()
.request_timeout(30)
.get("/", index)
.run();
}Implementations§
Source§impl App
impl App
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new App with default configuration.
Initialises structured logging on first call.
Sourcepub fn config(self, path: &str) -> Self
pub fn config(self, path: &str) -> Self
Point the application at a YAML config file.
Config is loaded (and merged with env vars) when .run() is called.
Sourcepub fn state<T: Send + Sync + 'static>(self, value: T) -> Self
pub fn state<T: Send + Sync + 'static>(self, value: T) -> Self
Register a shared value accessible in handlers via the Data<T> extractor.
Sourcepub fn route<H, T>(self, method: Method, path: &str, handler: H) -> Self
pub fn route<H, T>(self, method: Method, path: &str, handler: H) -> Self
Register a route for the given method and path.
pub fn get<H, T>(self, path: &str, handler: H) -> Self
pub fn post<H, T>(self, path: &str, handler: H) -> Self
pub fn put<H, T>(self, path: &str, handler: H) -> Self
pub fn delete<H, T>(self, path: &str, handler: H) -> Self
pub fn patch<H, T>(self, path: &str, handler: H) -> Self
Sourcepub fn controller<C: Controller>(self) -> Self
pub fn controller<C: Controller>(self) -> Self
Register a #[controller]-annotated struct.
At startup the framework will:
- Construct the controller via
C::from_state(&app_state). - Call
C::register(Arc::new(instance))to build its routes. - Nest those routes under
C::PREFIX.
Dependencies are resolved eagerly — a missing Data<T> will panic at
startup, not at request time (fail-fast).
Sourcepub fn routes(self, router: OxideRouter) -> Self
pub fn routes(self, router: OxideRouter) -> Self
Merge a pre-built OxideRouter into the application (flat, no prefix).
Sourcepub fn nest(self, prefix: &str, router: OxideRouter) -> Self
pub fn nest(self, prefix: &str, router: OxideRouter) -> Self
Nest a pre-built OxideRouter under the given path prefix.
Sourcepub fn rate_limit(self, max_requests: u64, window_secs: u64) -> Self
pub fn rate_limit(self, max_requests: u64, window_secs: u64) -> Self
Enable per-IP rate limiting.
Returns HTTP 429 with Retry-After header when the limit is exceeded.
Sourcepub fn cors_permissive(self) -> Self
pub fn cors_permissive(self) -> Self
Enable permissive CORS (allow any origin, method, and header).
Sourcepub fn cors_origins<I, S>(self, origins: I) -> Self
pub fn cors_origins<I, S>(self, origins: I) -> Self
Enable CORS with a specific set of allowed origins.
Sourcepub fn request_timeout(self, secs: u64) -> Self
pub fn request_timeout(self, secs: u64) -> Self
Set a maximum duration for request processing.
Sourcepub fn disable_request_logging(self) -> Self
pub fn disable_request_logging(self) -> Self
Disable the built-in per-request logging middleware.
Sourcepub fn auth(self, config: AuthConfig) -> Self
pub fn auth(self, config: AuthConfig) -> Self
Enable JWT authentication from Authorization: Bearer and/or a session cookie.
Inserts crate::auth::AuthClaims into request extensions when the token is valid.
Invalid or expired tokens return 401 before your handler runs.
Relative to state and hooks: application state is injected first, then JWT is validated, then
App::before / App::layer hooks, then the route handler.
Sourcepub fn before<F, Fut>(self, f: F) -> Self
pub fn before<F, Fut>(self, f: F) -> Self
Register a “before” hook that runs on every request.
The hook receives the request and a Next handle, and must produce a
response. Use it for auth checks, request mutation, short-circuit
responses, etc.
app.before(|req: Request, next: Next| async move {
println!("incoming: {} {}", req.method(), req.uri());
next.run(req).await
})Sourcepub fn scoped_state<F, Fut, T>(self, factory: F) -> Self
pub fn scoped_state<F, Fut, T>(self, factory: F) -> Self
Register a request-scoped dependency factory.
The factory closure is called on every incoming request, and its output
is automatically injected into the request extensions, making it available
to handlers via the Scoped<T> extractor.
Sourcepub fn after<F, Fut>(self, f: F) -> Self
pub fn after<F, Fut>(self, f: F) -> Self
Register an “after” hook that can transform every outgoing response.
app.after(|mut res: Response| async move {
res.headers_mut().insert("X-Powered-By", "Oxide".parse().unwrap());
res
})Sourcepub fn layer<L>(self, layer: L) -> Self
pub fn layer<L>(self, layer: L) -> Self
Add an arbitrary Tower Layer to the middleware stack.
The layer is positioned between state injection and the panic catcher,
so it has access to AppState and any panics it causes are caught.
Sourcepub fn run(self)
pub fn run(self)
Build and start the HTTP server. Blocks the current thread, creating a new Tokio runtime.
Sourcepub async fn into_test_server(self) -> TestServer
pub async fn into_test_server(self) -> TestServer
Start the server on a random port for integration testing.
Returns a TestServer with the bound address. The server runs in a
background tokio task and is stopped when the TestServer is dropped.