1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//! # Actus
//!
//! The pragmatic web framework for Rust: auditable controllers, persistent
//! services, real HTTP — out of the box. Built directly on [hyper] and
//! [tokio]; there is no separate server to run it on.
//!
//! Actus gives you a clear two-tier structure — a top-level routing blueprint
//! and self-contained controllers — while letting you mix REST, RPC-style
//! actions, and legacy URL migrations in the same codebase. A reviewer can
//! answer *what endpoints exist, what they require, and who can call them* by
//! reading two macros, without grepping for attribute decorators across files.
//!
//! # Philosophy
//!
//! Most Rust web frameworks are either unopinionated (you invent the structure)
//! or rigidly opinionated (you bend to their paradigm). Actus picks a middle:
//!
//! - **A clear hierarchy.** The whole URL layout is declared once, in
//! `app_routes! { ... }` — the entire backend is visible at a glance.
//! - **A clear unit of code.** Each controller owns a URL prefix and declares
//! its routes, access points, and parameters in one `routes! { ... }` block.
//! - **Pragmatism inside that structure.** REST verbs (`GET`/`POST`/`PUT`/
//! `DELETE`), RPC-style action names (`/charge`, `/refund`), path parameters
//! (`{id}`), and legacy URLs (`login.php`) all coexist in the same block.
//!
//! # Design principles
//!
//! - **Two kinds of cross-cutting concern get two shapes.** HTTP-protocol
//! concerns (CORS, body limits, compression) are named `Server::with_X(...)`
//! methods with their lifecycle position built in; application concerns
//! (logging, auth gates, request IDs, rate-limit policy) are `Middleware`.
//! You never have to position CORS in a stack.
//! - **Auditability over uniformity.** "What does this server do?" and "what
//! endpoints exist?" are answerable from `Server::new(...)` and the two
//! macros — without walking a chain of layers.
//! - **Explicit over magic.** No DI container, no extractors reaching into thin
//! air: the `app_routes!` `deps` block is constructor injection, and routes
//! are declared, not discovered.
//! - **HTTP correctness out of the box.** You shouldn't need to know that
//! compression goes outermost, or that the body cap gates the body parse —
//! that is framework knowledge, not application knowledge.
//! - **Policy-agnostic.** No roles, no `Access` enum, no built-in RBAC.
//! Authorization lives in your policy layer, called from a controller's
//! `prepare` hook or a handler.
//!
//! This crate is the façade you depend on. It re-exports the public API of the
//! implementation crates ([`actus-server`], [`actus-controller`],
//! [`actus-reply`]) and the two macros that declare your application's URL
//! surface. Add it with:
//!
//! ```toml
//! [dependencies]
//! actus = "1.0"
//! tokio = { version = "1", features = ["full"] }
//! serde_json = "1"
//! ```
//!
//! Optional features: `compression` (gzip/brotli responses), `websocket`
//! ([`ws::upgrade`]), and `openapi` (OpenAPI 3.x generation).
//!
//! # Quick start
//!
//! Two macros declare everything: `routes!` (one controller's API surface) and
//! `app_routes!` (the whole application's URL blueprint). A reviewer can see
//! every endpoint by reading just those two places.
//!
//! ```no_run
//! use actus::prelude::*;
//! use serde_json::json;
//!
//! // A controller owns a URL prefix and declares its routes in one block.
//! struct Greeter;
//!
//! #[controller]
//! impl Greeter {
//! routes! {
//! GET "" => index(),
//! GET "{name}" => greet(name: String),
//! }
//!
//! pub async fn index(&self) -> Reply {
//! reply!(json!({ "hello": "world" }))
//! }
//!
//! pub async fn greet(&self, name: String) -> Reply {
//! reply!(json!({ "hello": name }))
//! }
//! }
//!
//! // The application's URL blueprint, declared in one place. (The `deps`
//! // block — for injected services — is optional and omitted here.)
//! app_routes! {
//! routes {
//! "greet" => Greeter,
//! }
//! }
//!
//! // `init()` is generated by `app_routes!`; it builds the router.
//! #[tokio::main]
//! async fn main() -> actus::InitResult<()> {
//! let router = init().await?;
//! Server::new(router).run(3000).await?;
//! Ok(())
//! }
//! ```
//!
//! # What's in the box
//!
//! - **Hyper-based HTTP server** — `Server::run(port)` binds `127.0.0.1`;
//! `Server::run_on(addr)` binds anywhere (e.g. `0.0.0.0:port`). Graceful
//! shutdown on SIGTERM / SIGINT with a configurable drain deadline.
//! - **Two-macro routing** — `app_routes!` (the app's URL blueprint, with a
//! `deps` block for injected services) and `#[controller]` + `routes!`
//! (per-controller verbs, path patterns, typed query/body extraction, a
//! `prepare` hook, and per-controller `max_body_bytes` / `rate_limit`).
//! - **Longest-prefix routing** at arbitrary depth, with a trailing
//! `{...rest}` catch-all and distinct `404` vs `405` (carrying `Allow`).
//! - **Typed extraction & state** — query as a multimap, form-urlencoded
//! bodies, and typed path/query/body params; `prepare` hooks stash typed
//! values via `params.insert::<T>(...)` that handlers read back.
//! - **Replies** — `reply!` for JSON, chunked streams, and Server-Sent
//! Events; `WebError` for structured RFC 7807 `application/problem+json`.
//! - **HTTP-protocol features** — `Server::with_cors`, `with_compression`
//! (gzip/brotli, `compression` feature), a per-request timeout, and three
//! DoS guards (max connections, in-flight body budget, header-read timeout).
//! - **WebSocket** (`websocket` feature) — `ws::upgrade(...)` from a handler.
//! - **OpenAPI 3.x** (`openapi` feature) — `openapi::generate(...)` walks the
//! route tree and emits a spec.
//! - **Middleware** — `before` / `after` hooks via `Server::with_middleware`;
//! ships a `RequestLogger`.
//!
//! See the [`prelude`] for the common imports, and the [repository] for the
//! full guide — philosophy, framework comparisons, and the `examples/`
//! directory with auth, typed bodies, CORS, compression, WebSockets, SSE, and
//! middleware in working code.
//!
//! [hyper]: https://hyper.rs/
//! [tokio]: https://tokio.rs/
//! [`actus-server`]: https://docs.rs/actus-server
//! [`actus-controller`]: https://docs.rs/actus-controller
//! [`actus-reply`]: https://docs.rs/actus-reply
//! [repository]: https://github.com/uniweb/actus
pub use Finalizer;
// Re-exported at the crate root so the `app_routes!` macro can resolve
// `::actus::Router` / `::actus::RouterBuilder` from generated code without
// requiring downstream crates to depend on `actus-server` directly.
pub use ;
/// WebSocket support — [`ws::upgrade`], [`ws::WebSocket`], [`ws::Message`].
/// Available with the `websocket` feature.
pub use websocket as ws;
/// OpenAPI 3.x doc generation — [`openapi::generate`], [`openapi::Options`].
/// Available with the `openapi` feature.
pub use openapi;
/// Error type used by `app_routes!`'s generated `init()` for startup-time
/// failures (DB connection refused, env var missing, migrations failing,
/// etc.). Aliased to `anyhow::Error` so any error implementing
/// `std::error::Error + Send + Sync + 'static` converts via `?`, and the
/// generated `init()` slots cleanly into an `anyhow::Result<()>` `main`.
pub type InitError = Error;
/// `Result<T, actus::InitError>`. The macro-generated `init()` returns this.
pub type InitResult<T> = Result;
/// Implementation re-exports used by the procedural macros.
///
/// This module exists so generated code can refer to types from the
/// implementation crates (`actus-controller`, etc.) via stable absolute paths
/// like `::actus::__internal::Verb`. End users should not import from here —
/// use [`prelude`] instead.
/// Common imports for Actus applications.