rust_microservice/lib.rs
1//! # 📦 Rust Microservice
2//!
3//! **Rust Microservice Framework** is a high-performance Rust crate designed to simplify
4//! the creation, configuration, and initialization of microservice-oriented web servers.
5//! It provides a unified system for handling configuration from multiple sources
6//! and a web server bootstrap layer powered by `actix-web` and `tokio`.
7//!
8//! ## ✨ Features
9//!
10//! - **Multi-source configuration management**
11//! - YAML configuration file loading using `serde_yaml` and `config`
12//! - Environment variable overrides
13//! - Command-line parameter parsing using `clap`
14//! - Automatic deserialization into strongly typed structures using `serde`
15//!
16//! - **Web server initialization**
17//! - HTTP server powered by `actix-web`
18//! - Asynchronous runtime handled by `tokio`
19//! - Built-in routing integration for exposing microservice endpoints
20//! - Input/output serialization using `serde_json` and `serde-xml-rs`
21//!
22//! - **Extensible architecture**
23//! - Supports custom modules for controllers, services, repositories, and middleware
24//! - Easy integration with external crates and microservice ecosystems
25//!
26//! ## 🛠️ Configuration System
27//!
28//! The framework provides a configuration loader that merges settings from:
29//!
30//! 1. **YAML files** – typically `config.yaml` or environment-specific variations
31//! 2. **Environment variables** – allowing container-friendly overrides
32//! 3. **Command-line parameters** – using `clap` for high-level CLI ergonomics
33//!
34//! Configuration sources follow a layered precedence model:
35//!
36//! ```text
37//! Environment variables > CLI parameters > YAML configuration file
38//! ```
39//! After loading the configuration, the framework exposes a typed `Settings`
40//! instance for application modules and endpoint handlers.
41//!
42//! ## 🌐 Web SERVER Module
43//!
44//! The server module is responsible for:
45//!
46//! - Initializing the `actix-web` HTTP server
47//! - Registering routers and microservice endpoints
48//! - Managing middlewares and shared application state
49//! - Running the asynchronous runtime using `tokio::main` or a custom runtime
50//!
51//! This framework encourages a modular architecture where each microservice
52//! registers its own route handlers, serializers, and business logic.
53//!
54//! ## ⚙️ Serialization Support
55//!
56//! The crate includes seamless integration with:
57//!
58//! - **JSON** serialization/deserialization via `serde_json`
59//! - **XML** handling via `serde-xml-rs`
60//!
61//! These serializers allow exposing multiple content-types or supporting legacy systems.
62//!
63//! ## ⚡ Usage
64//!
65//! Add the crate dependency in your project's `Cargo.toml`:
66//!
67//! ```toml
68//! rust-microservice = "0.1.3"
69//! ```
70#![deny(clippy::unwrap_used)]
71#![deny(clippy::redundant_clone)]
72
73mod cmd;
74mod data;
75mod http;
76mod metrics;
77mod security;
78mod server;
79pub mod settings;
80pub mod test;
81
82#[derive(rust_embed::Embed)]
83#[folder = "assets"]
84pub(crate) struct Asset;
85
86pub use http::web::ServerWrappers;
87pub use http::web::create_server_wrappers as server_wrappers;
88pub use security::oauth2::LoginForm;
89pub use security::oauth2::Token;
90pub use server::Result;
91pub use server::Server;
92pub use server::ServerError;
93
94/// # 🔗 API Server Macro
95///
96/// The `api_server` macro is a procedural macro that generates the code necessary to
97/// start an `actix-web` HTTP server with support for OpenAPI documentation and
98/// a health check endpoint.
99///
100/// The `api_server` macro takes the following attributes:
101///
102/// - `controllers_path`: A comma-separated list of paths to modules containing
103/// controllers. The macro will recursively traverse the directories and generate
104/// code to register the controllers with the HTTP server.
105///
106/// - `openapi_title`: A string used as the title of the OpenAPI documentation.
107///
108/// - `openapi_api_description`: A string used as the description of the OpenAPI
109/// documentation.
110///
111/// - `database`: A boolean indicating whether the microservice should enable database
112/// integration. If set to `true`, the macro will generate code to initialize the
113/// database connection pool using the `sea_orm` crate.
114///
115/// - `banner`: A string used as the banner of the microservice. The banner is displayed
116/// in the server logs during startup.
117///
118/// Example of a minimal server bootstrap using this crate:
119///
120/// ```rust
121/// use rust_microservice::ServerApi;
122///
123/// #[ServerApi(
124/// controllers_path = "src/module, src/controllers",
125/// openapi_title = "🌐 Rest API Server",
126/// openapi_api_description = "Rest API OpenApi Documentation built with Rust 🦀.",
127/// database = "true",
128/// banner = r#"
129/// _~^~^~_ ___ ___ ____ ____
130/// \) / o o \ (/ / _ | / _ \ / _/ / __/___ ____ _ __ ___ ____
131/// '_ - _' / __ | / ___/_/ / _\ \ / -_)/ __/| |/ //! -_)/ __/
132/// / '-----' \ /_/ |_|/_/ /___/ /___/ \__//!_/ |___/ \__//!_/
133/// "#
134/// )]
135/// async fn start_server() -> rust_microservice::Result<(), String> {}
136/// ```
137pub use rust_microservice_macros::api_server as ServerApi;
138
139/// # 🛢️ Database Macro
140///
141/// The `database` macro is a procedural macro that injects a database connection
142/// into repository methods.
143///
144/// It expects two mandatory attributes:
145/// - `name`: selects which configured database connection will be used.
146/// - `error`: defines the error variant returned when the database is not configured or
147/// database connection cannot be found.
148///
149/// The macro injects a variable named `db` with type `&DatabaseConnection` (seaorm),
150/// so the function body can execute queries directly.
151///
152/// Example:
153///
154/// ```rust
155/// use rust_microservice::{Server, database};
156/// use thiserror::Error;
157///
158/// #[derive(Debug, Error)]
159/// pub enum UserError {
160/// #[error("Database is not configured")]
161/// DatabaseNotConfigured,
162///
163/// #[error("User not found")]
164/// NotFound,
165/// }
166///
167/// pub type Result<T, E = UserError> = std::result::Result<T, E>;
168///
169/// #[database(name = "api", error = "UserError::DatabaseNotConfigured")]
170/// pub async fn get_user_by_id(user_id: i32) -> Result<()> {
171///
172/// // Database will be injected here as `db`
173///
174/// //user::Entity::find_by_id(user_id)
175/// // .one(&db)
176/// // .await
177/// // .map_err(|_| UserError::NotFound)?
178/// // .ok_or(UserError::NotFound)
179/// // .map(Into::into)
180///
181/// Ok(())
182/// }
183/// ```
184pub use rust_microservice_macros::database;
185
186/// # 🔐 Secured Macro
187///
188/// The `Secured` macro protects `actix-web` endpoints by attaching an authentication middleware.
189///
190/// When applied to an endpoint, it validates:
191///
192/// - JWT presence in the request.
193/// - JWT signature.
194/// - JWT expiration time (`exp` claim).
195/// - JWT issuer (`iss` claim).
196/// - Required roles from the `authorize` expression.
197///
198/// ## Attribute Reference
199//
200/// Macro usage format:
201//
202/// ```no_run
203/// #[secured(method = "...", path = "...", authorize = "...")]
204/// ```
205///
206/// ### **`method`**
207///
208/// Defines the HTTP method used to map the endpoint in Actix-Web.
209///
210/// Supported values:
211///
212/// - `get`
213/// - `post`
214/// - `put`
215/// - `delete`
216/// - `head`
217/// - `connect`
218/// - `options`
219/// - `trace`
220/// - `patch`
221///
222/// ### **`path`**
223///
224/// Defines the endpoint path to be registered by Actix-Web.
225///
226/// Example:
227///
228/// `path = "/v1/user/{id}"`
229///
230/// ### **`authorize`**
231///
232/// Defines the required role rule that must be satisfied by roles present in the JWT.
233///
234/// Supported formats:
235///
236/// 1. `Single role`: validates one role in the token.
237///
238/// `authorize = "ROLE_ADMIN"`
239///
240/// 2. `hasAnyRole`: validates that at least one role in the list exists in the token.
241///
242/// `authorize = "hasAnyRole(ROLE_ADMIN, ROLE_USER)"`
243///
244/// 3. `hasAllRoles`: validates that all roles in the list exist in the token.
245///
246/// `authorize = "hasAllRoles(ROLE_ADMIN, ROLE_USER)"`
247///
248/// ## Examples
249///
250/// ### **`Single role`**:
251///
252/// ```no_run
253/// use rust_microservice::secured;
254/// use actix_web::{HttpResponse, delete, get, http::StatusCode, post, put, web};
255///
256/// #[secured(method = "post", path = "/v1/user", authorize = "ROLE_ADMIN")]
257/// pub async fn create_user_endpoint() -> HttpResponse {
258/// // handler body
259/// HttpResponse::Ok().finish()
260/// }
261/// ```
262///
263/// ### **`Any role`**:
264///
265/// ```no_run
266/// use rust_microservice::secured;
267/// use actix_web::{HttpResponse, delete, get, http::StatusCode, post, put, web};
268///
269/// #[secured(
270/// method = "get",
271/// path = "/v1/user/{id}",
272/// authorize = "hasAnyRole(ROLE_ADMIN, ROLE_USER)"
273/// )]
274/// pub async fn get_user_endpoint() -> HttpResponse {
275/// // handler body
276/// HttpResponse::Ok().finish()
277/// }
278/// ```
279///
280/// ### **`All roles`**:
281///
282/// ```no_run
283/// use rust_microservice::secured;
284/// use actix_web::{HttpResponse, delete, get, http::StatusCode, post, put, web};
285///
286/// #[secured(
287/// method = "delete",
288/// path = "/v1/user/{id}",
289/// authorize = "hasAllRoles(ROLE_ADMIN, ROLE_AUDITOR)"
290/// )]
291/// pub async fn delete_user_endpoint() -> HttpResponse {
292/// // handler body
293/// HttpResponse::Ok().finish()
294/// }
295/// ```
296pub use rust_microservice_macros::secured;