Skip to main content

arcly_http/
lib.rs

1//! **arcly-http** — NestJS ergonomics meets Rust safety & speed.
2//!
3//! An enterprise-grade web framework on [axum]: declarative controllers,
4//! zero-lock dependency injection, one shared request pipeline for every
5//! entry point, and the operational machinery (multi-tenancy, transactional
6//! outbox, ABAC, PII masking, field-level encryption, graceful shutdown
7//! governance) that production systems otherwise hand-roll.
8//!
9//! ```ignore
10//! use arcly_http::prelude::*;
11//!
12//! #[Injectable]
13//! pub struct GreetService;
14//! impl GreetService {
15//!     fn greet(&self, name: &str) -> String { format!("hello, {name}") }
16//! }
17//!
18//! #[Controller("/hello")]
19//! impl HelloController {
20//!     #[Get("/:name")]
21//!     async fn hello(&self, #[Param] name: String, svc: Inject<GreetService>) -> String {
22//!         svc.greet(&name)
23//!     }
24//! }
25//!
26//! #[Module(controllers(HelloController), providers(GreetService))]
27//! pub struct AppModule;
28//!
29//! #[tokio::main]
30//! async fn main() -> std::io::Result<()> {
31//!     App::launch::<AppModule>("0.0.0.0:3000").await // Swagger UI at /docs
32//! }
33//! ```
34//!
35//! ## Design invariants
36//!
37//! - **One request pipeline** — HTTP routes, plugin routes, and WebSocket
38//!   handshakes authenticate through the same boundary; a security fix lands
39//!   everywhere at once.
40//! - **No locks on the request path** — frozen `&'static` DI container,
41//!   atomics, and `ArcSwap` snapshots only.
42//! - **Handlers never see axum** — [`RequestContext`] is the only request
43//!   surface, so the HTTP layer can evolve without breaking user code.
44//!
45//! ## Module layout
46//!
47//! | Module          | Responsibility                                              |
48//! |-----------------|--------------------------------------------------------------|
49//! | [`app`]         | Launch contract, [`LaunchConfig`] governance knobs           |
50//! | [`auth`]        | Identity & access: JWT, cookies, sessions, OAuth2, ABAC, guards |
51//! | [`core`]        | DI engine + plugin lifecycle (HTTP-agnostic)                 |
52//! | [`web`]         | HTTP layer: boundary, context, errors, interceptors, CORS    |
53//! | [`data`]        | DB facade (SQLx/SeaORM/Diesel), tenancy, migrations, outbox  |
54//! | [`messaging`]   | Event consumer mesh, retries, dead-letter                    |
55//! | [`compliance`]  | PII masking + field-level envelope encryption                |
56//! | [`realtime`]    | WebSocket gateways + SSE                                      |
57//! | [`observability`] | Structured logs, Prometheus, OTLP, health, trace propagation |
58//! | [`resilience`]  | Circuit breaker, rate limiting, bulkhead, distributed locks  |
59//! | [`security`]    | Security headers                                              |
60//!
61//! ## Cargo features
62//!
63//! | Feature | Effect |
64//! |---|---|
65//! | *(none)* | Full framework, no database driver |
66//! | `db-sqlx` / `db-sqlx-postgres` / `db-sqlx-mysql` / `db-sqlx-sqlite` | SQLx-backed [`data`] layer |
67//! | `db-seaorm` | SeaORM driver |
68//! | `db-diesel` | Diesel (r2d2) driver |
69//!
70//! Most applications only need `use arcly_http::prelude::*;`.
71//!
72//! [axum]: https://docs.rs/axum
73
74pub mod app;
75pub mod auth;
76pub mod compliance;
77pub mod core;
78pub mod data;
79pub mod event;
80pub mod http;
81pub mod messaging;
82pub mod observability;
83pub mod openapi;
84pub mod realtime;
85pub mod resilience;
86pub mod security;
87pub mod validation;
88pub mod web;
89
90// ─── Path-compat shims ─────────────────────────────────────────────────────────
91// The auth subsystem was consolidated from five root files into `auth/`.
92// These re-exports keep every pre-existing import path compiling unchanged:
93// `arcly_http::cookie::CookieService`, `arcly_http::guards::Guard`, etc.
94pub use auth::cookie;
95pub use auth::guards;
96pub use auth::oauth;
97pub use auth::session;
98
99// Convenience re-exports.
100pub use core::plugins;
101pub use web::cache;
102pub use web::interceptors;
103
104// Re-exports needed by macro expansions.
105#[doc(hidden)]
106pub use axum as __axum;
107pub use futures;
108pub use inventory;
109pub use schemars;
110pub use serde_json;
111pub use validator;
112
113pub use app::{App, LaunchConfig};
114pub use web::{Error, RequestContext};
115
116#[doc(hidden)]
117#[inline]
118pub fn __schema_for<T: schemars::JsonSchema>() -> serde_json::Value {
119    serde_json::to_value(schemars::schema_for!(T)).unwrap_or(serde_json::Value::Null)
120}
121
122/// Single stable surface for `arcly-http-macros` codegen.
123///
124/// Every symbol the proc-macros emit is re-exported here, so internal files
125/// can move freely without touching the macro crate — only this module's
126/// `pub use` lines need to follow.
127#[doc(hidden)]
128pub mod __macro_support {
129    pub use crate::auth::guards::Guard;
130    pub use crate::auth::policy::check_policies;
131    pub use crate::compliance::crypto::EncryptRecord;
132    pub use crate::compliance::masking::mask_response;
133    pub use crate::core::engine::*;
134    pub use crate::data::tx::run_transactional;
135    pub use crate::http::Json;
136    pub use crate::messaging::{EventContext, EventHandlerDescriptor};
137    pub use crate::observability::audit::emit_route_audit;
138    pub use crate::realtime::gateway::{GatewayDescriptor, GatewayRuntime, MessageHandler};
139    pub use crate::realtime::{ArclyGateway, WsClient};
140    pub use crate::resilience::timeout::run_with_timeout;
141    pub use crate::resilience::{BreakerOpen, CircuitBreaker};
142    pub use crate::web::context::RequestContext;
143    pub use crate::web::extract::*;
144    pub use crate::web::idempotency::run_idempotent;
145    pub use crate::web::interceptors::{Interceptor, NextHandler};
146    pub use crate::web::Error;
147}
148
149/// `use arcly_http::prelude::*;` brings in everything a user needs.
150pub mod prelude {
151    pub use crate::app::{App, LaunchConfig};
152    pub use crate::auth::cookie::{CookieConfig, CookieService, SameSite};
153    pub use crate::auth::guards::{
154        JwtAuthGuard, RoleGuard, SessionAuthGuard, JWT_AUTH, SESSION_AUTH,
155    };
156    pub use crate::auth::oauth::{OAuth2Provider, OAuth2Service, OAuth2UserInfo};
157    pub use crate::auth::policy::{
158        check_policies, Decision, EnvAttributes, PolicyEngine, PolicyInput, PolicySet, PolicySource,
159    };
160    pub use crate::auth::secrets::{spawn_secret_watcher, Rotating, SecretSource, SecretVersion};
161    pub use crate::auth::session::{Session, SessionConfig, SessionManager, SessionStore};
162    pub use crate::auth::{JwtConfig, JwtService};
163    pub use crate::cache::{stats as cache_stats, CacheInterceptor, CacheStats};
164    pub use crate::compliance::{
165        CryptoError, CryptoVault, DataKey, EncryptRecord, EncryptedField, KekSource, KeyId,
166        MaskRule, MaskStrategy, Masker, MaskingPolicy,
167    };
168    pub use crate::core::engine::FrozenDiContainer;
169    pub use crate::core::plugins::{ArclyPlugin, ArclyPluginContext, PluginError, PluginStage};
170    pub use crate::data::db::{ArclyDbPool, DbDriver, OwnedDbConn};
171    #[cfg(feature = "db-sqlx")]
172    pub use crate::data::migrate::{Migration, MigrationReport, MigrationRunner};
173    pub use crate::data::outbox::{
174        with_transaction, OutboxEntry, OutboxPublisher, OutboxRelay, OutboxStore, OutboxTx,
175        TransactionalDataSource,
176    };
177    pub use crate::data::tx::{in_transaction, with_current_tx, ArclyTransaction};
178    pub use crate::data::{
179        AccessIntent, DataError, DataSource, DataSourceRegistry, ReadAfterWritePin,
180    };
181    pub use crate::http::{IntoResponse, Json, Response};
182    pub use crate::interceptors::{
183        EnvelopeResponse, Interceptor, LatencyLog, NextHandler, TelemetryLog, TraceInterceptor,
184    };
185    pub use crate::messaging::{
186        ConsumerRuntime, EventContext, EventHandlerDescriptor, InboundMessage, MessageTransport,
187    };
188    pub use crate::observability::audit::{AuditOutcome, AuditPipeline, AuditRecord, AuditSink};
189    pub use crate::observability::health::{HealthCheck, HealthRegistry, HealthStatus};
190    pub use crate::observability::plugin::ArclyObservabilityPlugin;
191    pub use crate::openapi::{ApiKeyIn, OpenApiInfo, SecurityScheme};
192    pub use crate::resilience::{
193        Bulkhead, DLockBackend, DistributedLock, DistributedRateLimit, FailurePolicy, LockGuard,
194        RateDecision, RateLimit, RateLimitBackend,
195    };
196    pub use crate::security::{configure as configure_security, FrameOptions, SecurityConfig};
197    pub use crate::validation::Validated;
198    pub use crate::web::boundary::BoundaryFilter;
199    pub use crate::web::cors::CorsConfig;
200    pub use crate::web::dynamic::{DynamicRouteTable, DYNAMIC_PREFIX};
201    pub use crate::web::error::{
202        BadRequest, Conflict, FieldError, Forbidden, GatewayTimeout, HttpError, HttpException,
203        Internal, NotFound, ProblemDetails, ServiceUnavailable, TooManyRequests, Unauthorized,
204        Validation,
205    };
206    pub use crate::web::idempotency::{IdempotencyDecision, IdempotencyStore};
207    pub use crate::web::responses::{Accepted, Created, NoContent};
208    pub use crate::web::tenant::{
209        TenantConfig, TenantGuard, TenantId, TenantRegistry, TenantStrategy, TENANT,
210    };
211    pub use crate::web::{Error, Inject, RequestContext};
212    pub use arcly_http_macros::{
213        circuit_breaker, AuditLog, CacheKey, CacheTTL, Controller, Delete, Deprecated,
214        EncryptFields, EventConsumer, EventPattern, Get, Idempotent, Injectable, MaskFields,
215        Module, Patch, Post, Put, RequirePolicies, Timeout, Transactional, UseInterceptors,
216        Version,
217    };
218    pub use schemars::JsonSchema;
219    pub use validator::Validate;
220}