Skip to main content

App

Struct App 

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

Builder for an Aro web application.

Wraps an Axum Router and applies framework defaults (tracing middleware, JSON error fallbacks) while allowing full customization.

§Example

use aro_web::App;
use axum::Router;
use axum::routing::get;

App::new()
    .routes(Router::new().route("/", get(|| async { "ok" })))
    .serve("0.0.0.0:3000".parse()?)
    .await?;

Implementations§

Source§

impl App

Source

pub fn new() -> Self

Create a new App with default settings.

Source

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

Merge the given router’s routes into the application.

Can be called multiple times to compose routes from different modules.

Source

pub fn state(self, state: AroState) -> Self

Set the application state for dependency injection.

The state is made available to handlers via the Dep<T> extractor.

Registrations from register take precedence over entries with the same type when both are present at build time.

Source

pub fn register<T: ?Sized + 'static>(self, service: Arc<T>) -> Self
where Arc<T>: Send + Sync + Clone + 'static,

Register a dependency for injection.

The type parameter T should be a trait object type (e.g. dyn UserRepo). Registered dependencies are accumulated internally and merged into the final AroState at build time. When combined with state, registrations from this method take precedence over entries with the same type from external state.

§Example
// Domain types (`UserRepo`, `UserRepoImpl`) come from your app.
App::new()
    .register::<dyn UserRepo>(Arc::new(UserRepoImpl::new(pool)))
    .routes_with_state(routes)
    .build()
Source

pub fn routes_with_state(self, router: Router<AroState>) -> Self

Merge routes that require AroState into the application.

Use this for routers containing handlers that use Dep<T> extractors. The state must be set via state before calling build.

Source

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

Add a tower Layer to the application.

User layers wrap the default middleware stack (outermost). They execute in the order they are added and apply to all routes, including those registered via routes_with_state. Each call wraps the stack, so the last layer added is outermost on inbound requests.

Source

pub fn body_limit(self, max_bytes: usize) -> Self

Set the maximum allowed request body size in bytes.

Applies DefaultBodyLimit::max as a global layer, overriding Axum’s default 2 MB limit for extractors like Json, Form, and Bytes. Individual routes can still override this with a per-route DefaultBodyLimit layer.

§Example
use aro_web::App;
use axum::Router;

let _app = App::new()
    .body_limit(10 * 1024 * 1024) // 10 MB
    .routes(Router::new())
    .build();
Source

pub fn config<T: DeserializeOwned + Send + Sync + 'static>( self, ) -> Result<Self, ConfigError>

Load layered configuration and register it as a dependency.

Uses load_config to build T from environment variables and config files, then registers the result so it can be extracted with Dep<T>.

§Errors

Returns an error if configuration loading or deserialization fails.

Source

pub fn on_startup<F>(self, hook: F) -> Self
where F: FnOnce(Arc<AroState>) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error>>>>> + Send + 'static,

Register an async startup hook.

Hooks run in the order they are registered during serve() or build_with_hooks(), before the TCP listener is bound. Each hook receives a shared reference to the resolved AroState. If any hook returns an error, the server will not start and serve() will return the error.

§Example
use aro_web::App;
use axum::Router;

App::new()
    .on_startup(|_state| Box::pin(async move { Ok(()) }))
    .routes(Router::new())
    .serve("127.0.0.1:0".parse()?)
    .await?;
Source

pub fn timeout(self, duration: Duration) -> Self

Apply a request timeout to all routes.

Requests that are not completed within the given duration will receive a 408 Request Timeout response.

This is the canonical builder entry point: the timeout applies to all routes, including stateful DI routes added via routes_with_state.

For manual Router::layer(...) composition, see crate::middleware::timeout.

§Example
use std::time::Duration;

use aro_web::App;
use axum::Router;

let _app = App::new()
    .routes(Router::new())
    .timeout(Duration::from_secs(30))
    .build();
Source

pub fn without_defaults(self) -> Self

Disable the default middleware stack (TraceLayer).

Call this if you want full control over the middleware pipeline. The JSON fallback handler is always applied.

Source

pub fn build(self) -> Router

Build the final Router, applying default middleware.

The default middleware stack includes:

  • JSON 404/405 fallback handlers for unmatched routes and unsupported methods
  • TraceLayer from tower-http for request/response logging

Note: Startup hooks registered via on_startup are not executed by build(). Use build_with_hooks() or serve() to run them.

Source

pub async fn build_with_hooks(self) -> Result<Router, Box<dyn Error>>

Build the final Router, running all startup hooks first.

This is the same as build() but runs all registered startup hooks in order before returning the router. Use this in tests when your app relies on startup hooks (e.g., database migrations).

§Errors

Returns an error if any startup hook fails.

§Example
use aro_web::App;
use axum::Router;

let _router = App::new()
    .on_startup(|_state| Box::pin(async move { Ok(()) }))
    .routes(Router::new())
    .build_with_hooks()
    .await?;
Source

pub async fn serve(self, addr: SocketAddr) -> Result<(), Box<dyn Error>>

Build and start serving the application.

Runs all registered startup hooks in order, then binds to the given address and serves with graceful shutdown (handles SIGINT/Ctrl+C and SIGTERM).

Note: Like build_with_hooks, this runs startup hooks. build alone does not.

If any startup hook returns an error, the server is not started and the error is returned.

Trait Implementations§

Source§

impl Default for App

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for App

§

impl !Sync for App

§

impl !UnwindSafe for App

§

impl Freeze for App

§

impl Send for App

§

impl Unpin for App

§

impl UnsafeUnpin 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<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

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> ServiceExt for T

Source§

fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using HTTP status codes. Read more
Source§

fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using gRPC headers. Read more
Source§

fn override_request_header<M>( self, header_name: HeaderName, make: M, ) -> SetRequestHeader<Self, M>
where Self: Sized,

Insert a header into the request. Read more
Source§

fn append_request_header<M>( self, header_name: HeaderName, make: M, ) -> SetRequestHeader<Self, M>
where Self: Sized,

Append a header into the request. Read more
Source§

fn insert_request_header_if_not_present<M>( self, header_name: HeaderName, make: M, ) -> SetRequestHeader<Self, M>
where Self: Sized,

Insert a header into the request, if the header is not already present. Read more
Source§

fn override_response_header<M>( self, header_name: HeaderName, make: M, ) -> SetResponseHeader<Self, M>
where Self: Sized,

Insert a header into the response. Read more
Source§

fn append_response_header<M>( self, header_name: HeaderName, make: M, ) -> SetResponseHeader<Self, M>
where Self: Sized,

Append a header into the response. Read more
Source§

fn insert_response_header_if_not_present<M>( self, header_name: HeaderName, make: M, ) -> SetResponseHeader<Self, M>
where Self: Sized,

Insert a header into the response, if the header is not already present. Read more
Source§

fn set_request_id<M>( self, header_name: HeaderName, make_request_id: M, ) -> SetRequestId<Self, M>
where Self: Sized, M: MakeRequestId,

Add request id header and extension. Read more
Source§

fn set_x_request_id<M>(self, make_request_id: M) -> SetRequestId<Self, M>
where Self: Sized, M: MakeRequestId,

Add request id header and extension, using x-request-id as the header name. Read more
Source§

fn propagate_request_id( self, header_name: HeaderName, ) -> PropagateRequestId<Self>
where Self: Sized,

Propgate request ids from requests to responses. Read more
Source§

fn propagate_x_request_id(self) -> PropagateRequestId<Self>
where Self: Sized,

Propgate request ids from requests to responses, using x-request-id as the header name. 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<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