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
//! caslex is a set of tools for creating web services.
//!
//! ## High level features
//! * HTTP web server
//! * HTTP middlewares (auth, metrics, trace)
//! * Builtin OpenAPI visualizer
//! * Errors handling
//! * JWT
//! * Postgres Pool
//! * Observability
//! * Extra utils
//!
//! ## Example
//!
//! The “Hello, World!” of caslex is:
//!
//! ```rust,no_run
//! use caslex::server::{Config, Server};
//! use utoipa_axum::{router::OpenApiRouter, routes};
//!
//! #[utoipa::path(
//! get,
//! path = "/",
//! responses(
//! (status = 200, description = "Ok")
//! )
//! )]
//! async fn handler() -> &'static str {
//! "Hello, World!"
//! }
//!
//! #[tokio::main]
//! async fn main() {
//! let config = Config::parse();
//! let router = OpenApiRouter::new().routes(routes!(handler));
//!
//! let result = Server::new(config).router(router).run().await;
//! match result {
//! Ok(_) => std::process::exit(0),
//! Err(_) => {
//! std::process::exit(1);
//! }
//! }
//! }
//! ```
//!
//! Note using `#[tokio::main]` requires you enable tokio’s `macros` and `rt-multi-thread` features
//! or just `full` to enable all features (`cargo add tokio --features macros,rt-multi-thread`).
//!
//! # Errors
//!
//! Example of how to create custom API error.
//!
//! ```rust,no_run
//! use std::{error::Error as StdError, fmt, fmt::Display};
//!
//! use caslex::{
//! errors::{AppError, DefaultError},
//! server::{Config, Server},
//! };
//! use http::StatusCode;
//! use utoipa_axum::{router::OpenApiRouter, routes};
//!
//! async fn error_handler() -> Result<&'static str, DefaultError> {
//! Err(DefaultError::AppError(&CustomError::TestErrorOne))
//! }
//!
//! #[derive(Debug)]
//! enum CustomError {
//! TestErrorOne,
//! }
//!
//! impl StdError for CustomError {}
//!
//! impl Display for CustomError {
//! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//! write!(
//! f,
//! "error: status={} kind={} details={}",
//! self.status(),
//! self.kind(),
//! self.details()
//! )
//! }
//! }
//!
//! impl AppError for CustomError {
//! fn status(&self) -> StatusCode {
//! match self {
//! CustomError::TestErrorOne => StatusCode::BAD_REQUEST,
//! }
//! }
//!
//! fn details(&self) -> String {
//! match self {
//! CustomError::TestErrorOne => "my test error".to_owned(),
//! }
//! }
//!
//! fn kind(&self) -> String {
//! match self {
//! CustomError::TestErrorOne => "test_error".to_owned(),
//! }
//! }
//! }
//! ```
//!
//! # Middlewares
//!
//! ```rust,no_run
//! use caslex::{errors::DefaultError, middlewares::auth::Claims};
//!
//! async fn decode_handler(_: Claims) {
//! // will be error before enter the body
//! }
//! ```
//!
//! # Examples
//!
//! The caslex repo contains a number of [examples] that show how to put all the pieces together.
//!
//! # Feature flags
//!
//! caslex uses a set of [feature flags] to reduce the amount of compiled and
//! optional dependencies.
//!
//! The following optional features are available:
//!
//! Name | Description | Default?
//! ---|---|---
//! `auth` | Enables auth middleware | No
//!
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/features.html#the-features-section
//! [examples]: https://github.com/mkbeh/caslex/tree/main/examples