Skip to main content

App

Struct App 

Source
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

Source

pub fn new() -> Self

Create a new App with default configuration.

Initialises structured logging on first call.

Source

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.

Source

pub fn state<T: Send + Sync + 'static>(self, value: T) -> Self

Register a shared value accessible in handlers via the Data<T> extractor.

Source

pub fn route<H, T>(self, method: Method, path: &str, handler: H) -> Self
where H: Handler<T, ()>, T: 'static,

Register a route for the given method and path.

Source

pub fn get<H, T>(self, path: &str, handler: H) -> Self
where H: Handler<T, ()>, T: 'static,

Source

pub fn post<H, T>(self, path: &str, handler: H) -> Self
where H: Handler<T, ()>, T: 'static,

Source

pub fn put<H, T>(self, path: &str, handler: H) -> Self
where H: Handler<T, ()>, T: 'static,

Source

pub fn delete<H, T>(self, path: &str, handler: H) -> Self
where H: Handler<T, ()>, T: 'static,

Source

pub fn patch<H, T>(self, path: &str, handler: H) -> Self
where H: Handler<T, ()>, T: 'static,

Source

pub fn controller<C: Controller>(self) -> Self

Register a #[controller]-annotated struct.

At startup the framework will:

  1. Construct the controller via C::from_state(&app_state).
  2. Call C::register(Arc::new(instance)) to build its routes.
  3. Nest those routes under C::PREFIX.

Dependencies are resolved eagerly — a missing Data<T> will panic at startup, not at request time (fail-fast).

Source

pub fn routes(self, router: OxideRouter) -> Self

Merge a pre-built OxideRouter into the application (flat, no prefix).

Source

pub fn nest(self, prefix: &str, router: OxideRouter) -> Self

Nest a pre-built OxideRouter under the given path prefix.

Source

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.

Source

pub fn cors_permissive(self) -> Self

Enable permissive CORS (allow any origin, method, and header).

Source

pub fn cors_origins<I, S>(self, origins: I) -> Self
where I: IntoIterator<Item = S>, S: AsRef<str>,

Enable CORS with a specific set of allowed origins.

Source

pub fn request_timeout(self, secs: u64) -> Self

Set a maximum duration for request processing.

Source

pub fn disable_request_logging(self) -> Self

Disable the built-in per-request logging middleware.

Source

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.

Source

pub fn before<F, Fut>(self, f: F) -> Self
where F: Fn(Request, Next) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Response> + Send + 'static,

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
})
Source

pub fn scoped_state<F, Fut, T>(self, factory: F) -> Self
where F: Fn(&Parts) -> Fut + Send + Sync + 'static, Fut: Future<Output = T> + Send + 'static, T: Clone + Send + Sync + 'static,

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.

Source

pub fn after<F, Fut>(self, f: F) -> Self
where F: Fn(Response) -> Fut + Clone + Send + Sync + 'static, Fut: Future<Output = Response> + Send + 'static,

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
})
Source

pub fn layer<L>(self, layer: L) -> Self
where L: Layer<Route> + Clone + Send + Sync + 'static, L::Service: Service<Request, Response = Response, Error = Infallible> + Clone + Send + Sync + 'static, <L::Service as Service<Request>>::Future: Send + 'static,

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.

Source

pub fn run(self)

Build and start the HTTP server. Blocks the current thread, creating a new Tokio runtime.

Source

pub async fn serve(self)

Build and start the HTTP server using the current Tokio runtime.

Source

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.

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<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, 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<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
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,