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
//! # axa
//!
//! Small shared library for services built directly on Axum.
//!
//! This is a library, not a framework. A service's `main.rs` stays ordinary
//! Axum and calls into this crate: there are no lifecycle hooks or macros, and
//! [`AppContext`] is a plain struct passed as ordinary Axum state. Every piece
//! can be read, replaced, or left out on its own.
//!
//! # Example
//!
//! Declare routes, turn them into a plain [`axum::Router`] under the standard
//! middleware, and serve it:
//!
//! ```
//! use axa::prelude::*;
//! use axa::config::{Config, Defaults};
//! use axa::Environment;
//!
//! async fn hello() -> Result<Response> {
//! format::json(serde_json::json!({ "hello": "world" }))
//! }
//!
//! # fn main() -> Result<()> {
//! let environment = Environment::Test;
//! let config = Config::from_lookup(
//! &environment,
//! &Defaults { database: "", ..Defaults::default() },
//! |_| None,
//! )?;
//! # #[cfg(axa_db = "none")] {
//! let ctx = AppContext::new(environment, (), config);
//! let router = AppRoutes::with_default_routes()
//! .add_route(Routes::new().prefix("/api").add("/hello", get(hello)))
//! .into_app(ctx)?;
//! # let _: axum::Router = router;
//! # }
//! # Ok(())
//! # }
//! ```
//!
//! # Features
//!
//! | Feature | Adds |
//! |---|---|
//! | `queue` | The Postgres job queue in [`queue`] |
//! | `sea-orm` | A SeaORM-backed [`AppContext`], with `axa-seaorm` as `axa::seaorm` |
//! | `redis` | A Redis cache with mandatory expiry, as `axa::redis` |
//! | `diesel` | Diesel pooling, migrations, and test resets in pure Rust, as `axa::diesel` |
//! | `tera` | Tera templates with safe escaping, as `axa::tera` |
//! | `tracing` | Redaction, request tracking, and asynchronous diagnostics, as `axa::tracing` |
//! | `session` | Web sessions with safe defaults, as `axa::session` |
//! | `sqlx` | Pooling, migrations, and test resets, as `axa::sqlx` |
//! | `idempotency` | `Idempotency-Key` handling over Postgres, as `axa::idempotency` |
//! | `openapi` | `OpenAPI` documents, a pinned Swagger UI, and drift checks, as `axa::openapi` |
//! | `opentelemetry` | OTLP export of traces and request metrics, as `axa::opentelemetry` |
//! | `outbox` | A transactional outbox and relay on Postgres that keeps a record, as `axa::outbox` |
//! | `outbox-encryption` | `outbox`, with payloads sealed at rest under the service's keys |
//! | `cursor-pagination` | Signed cursor pages with no total, and `LIKE` escaping, as `axa::cursor_pagination` |
//! | `keycloak` | Keycloak bearer authentication and ABAC enforcement, as `axa::keycloak` |
//! | `paseto` | PASETO bearer authentication and ABAC enforcement, as `axa::paseto` |
//! | `problem` | Nothing: RFC 9457 problem details are always `axa::problem`, as [`Error`] answers with them |
//! | `prometheus` | Prometheus text exposition, as `axa::prometheus` |
//! | `ratelimit` | In-process request limits and failed-login lockout, as `axa::ratelimit` |
//! | `versioning` | `Accepts-version` negotiation, as `axa::versioning` |
//!
//! # Origin
//!
//! The behaviours here are the ones the Main X Index services relied on in
//! [Loco](https://loco.rs). They were written afresh rather than copied, so
//! this crate can keep its own licence terms.
/// Compiles the Rust examples in `README.md`, so they cannot go stale.
;
/// Compiles the Rust examples in the guides, so they cannot go stale.
;
/// Compiles the Rust examples in the idempotency keys guide.
;
/// Compiles the Rust examples in the skill. Its first example passes `()` as the
/// database, so it builds only with no database feature, as the README's do.
;
pub use axa_accepts_version_negotiation as versioning;
pub use axa_cursor_pagination as cursor_pagination;
pub use axa_diesel as diesel;
pub use axa_environment as environment;
pub use axa_idempotency_key as idempotency;
pub use axa_keycloak_auth as keycloak;
pub use axa_openapi_docs as openapi;
pub use axa_opentelemetry as opentelemetry;
pub use axa_paseto_auth as paseto;
pub use axa_problem as problem;
pub use axa_prometheus_metrics as prometheus;
pub use axa_redis_cache as redis;
pub use axa_request_rate_limit as ratelimit;
pub use axa_seaorm as seaorm;
pub use ;
pub use axa_sqlx as sqlx;
pub use axa_tera_templates as tera;
pub use axa_toasty as toasty;
pub use axa_tracing as tracing;
pub use axa_transactional_outbox as outbox;
pub use axa_web_session as session;
pub use AppContext;
pub use Environment;
pub use ;