velvet-web 0.8.17

Wrapper stack for webapp apis
Documentation
//! # Velvet
//!
//! A layer of republish and small functions to remove some boilerplate on web stacks.
//!
//! For a reference/example of a project using it:
//! <https://codeberg.org/raffaeleragni/veltes>
//!
//! Other sample projects that use velvet:
//! - <https://codeberg.org/raffaeleragni/forumfactor>
//! - <https://codeberg.org/raffaeleragni/norush>
//!
//! ## Stack used
//!
//!   - WEB: `Axum`
//!   - DB: `sqlx`(postgres,sqlite,mysql)
//!   - Templating: `Askama` (folder templates/)
//!   - Telemetry: `sentry` supported
//!   - Metrics: `prometheus` under `/metrics/prometheus`
//!
//! The askama templates and the static `RustEmbed` will be compiled in and not required at runtime.
//!
//! The sqlx migrations are not embedded, and will be needed at runtime.
//!
//! Proc macros cannot be transferred transitively, so crates need to be added again at project root in order to access them. For example `tokio` or `serde`.
//!
//! ## Base route setup
//!
//! ```no_run
//! use velvet_web::prelude::*;
//!
//! #[tokio::main]
//! async fn main() {
//!     App::new().route("/", get(index)).start().await.unwrap();
//! }
//!
//! async fn index() -> impl IntoResponse {
//!     "Hello World"
//! }
//! ```
//!
//! ## Simple example
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/01_base.rs)
//!
//! ## Logging
//!
//! Default log level is `error`. To change the level use the env var `RUST_LOG=info|debug|warn`.
//!
//! To get structured logging (`json` logs) pass env var `STRUCTURED_LOGGING=true`.
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/02_logging.rs)
//!
//! ## Add custom metrics
//!
//! Metrics available at `/metrics/prometheus`.
//! The custom metrics will be visible as soon as the first use happens, but only when used after App startup, not before.
//! For example, all the routes will work when used like this.
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/03_metrics.rs)
//!
//! ## Add a database
//!
//! Adding a `.env` file with `DATABASE_URL=sqlite::memory:`, and enabling the feature `sqlite` in crate `velvet_web`.
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/04_database.rs)
//!
//! ## Use an HTTP Client
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/05_client.rs)
//!
//! ## Check JWT token (from bearer or cookies)
//!
//! Adding a `.env` file with `JWT_SECRET=secret` and enabling the feature `auth` in `velvet_web`.
//!
//! JWK urls are also supported with a different enum initialization `JWT::JWK.setup().await?`.
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/06_token.rs)
//!
//! ## Support for static files
//!
//! Need to include crate `rust_embed` as this uses proc macros.
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/07_statics.rs)
//!
//! ## A more complete example
//!
//! Using also Askama templates, and JWT through cookie setting.
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/08_full.rs)
//!
//! ## Testing routes
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/09_testing.rs)
//!
//! ## Embedded login(and registration) flow
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/10_login.rs)
//!
//! ## Sending mails
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/11_mail.rs)
//!
//! ## Login with email confirmation link
//!
//! [example](https://codeberg.org/raffaeleragni/velvet/src/branch/main/examples/12_login_mail.rs)
//!
//! ## Default routes already implemented
//!
//!   - Status (no-op): http `GET /status/liveness`
//!   - Metrics: http `GET /metrics/prometheus`
//!
//! ## ENV vars
//!
//!   - `SERVER_BIND`: default (0.0.0.0) bind network for which to listen on
//!   - `SERVER_PORT`: (default 8080) port for which to listen on
//!   - `DATABASE_URL`: postgres://user:pass@host:port/database (if database used) or `sqlite::memory:...`
//!   - `DATABASE_MAX_CONNECTIONS`: (default 1)
//!   - `STRUCTURED_LOGGING`: true|false (default false)
//!   - `SENTRY_URL`: url inclusive of key for sending telemetry to sentry
//!
//! ## To setup TLS use env vars:
//!
//!   - `TLS=true` (or any string)
//!   - `TLS_PEM_CERT=cert.pem`
//!   - `TLS_PEM_KEY=key.pem`
//!
//! ## To setup SMTP/MAIL:
//!
//! Mail setup works only with TLS (port 465 if not set)
//!
//!   - `MAIL_FROM=test@test.com`
//!   - `MAIL_HOST=localhost`
//!   - `MAIL_PORT=2525`
//!   - `MAIL_USERNAME=user`
//!   - `MAIL_PASSWORD=password`
//!   - `MAIL_ACCEPT_INVALID_CERTS=true` if in develop mode
//!

mod app;
#[cfg(feature = "auth")]
mod auth;
mod client;
#[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
mod db;
mod errors;
mod mail;
mod metrics;

#[macro_use]
pub mod prelude {
    pub use super::app::App;
    pub use super::app::BuiltApp;
    #[cfg(feature = "auth")]
    pub use super::app::TestLoginAsBearer;
    #[cfg(feature = "login")]
    pub use super::app::TestLoginAsCookie;
    pub use super::client::client;
    pub use super::errors::AppError;
    pub use super::errors::AppResult;
    pub use super::errors::TemplateResponse;
    pub use super::metrics::metric_counter;
    pub use super::metrics::metric_gauge;
    pub use super::metrics::metric_histogram;
    pub use askama::Template;
    pub use axum::extract::{Form, Json, Path, Query};
    pub use axum::http::HeaderMap;
    pub use axum::http::HeaderName;
    pub use axum::http::HeaderValue;
    pub use axum::http::StatusCode;
    pub use axum::response::IntoResponse;
    pub use axum::response::Redirect;
    pub use axum::routing::{delete, get, head, options, patch, post, put, trace};
    pub use axum::{Extension, Router};
    pub use axum_test::TestServer;
    pub use reqwest::Client;
    pub use reqwest::Method as ClientMethod;
    pub use rust_embed::RustEmbed;
    pub use serde::{Deserialize, Serialize};
    pub use tracing::{Level, debug, error, info, instrument, span, trace, warn};
    pub use valuable::Valuable;

    pub use super::mail::mailer;
    pub use lettre::Message as MailMessage;
    pub use lettre::SmtpTransport as MailTransport;
    pub use lettre::Transport as MailTransportTrait;
    pub use lettre::message::header::ContentType as MailContentType;

    #[cfg(feature = "mysql")]
    pub use super::db::mysql;
    #[cfg(feature = "postgres")]
    pub use super::db::postgres;
    #[cfg(feature = "sqlite")]
    pub use super::db::sqlite;
    #[cfg(feature = "mysql")]
    pub use sqlx::MySql;
    #[cfg(feature = "postgres")]
    pub use sqlx::Postgres;
    #[cfg(feature = "sqlite")]
    pub use sqlx::Sqlite;
    #[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
    pub use sqlx::{Pool, query, query_as};

    #[cfg(feature = "auth")]
    pub use super::auth::AuthResult;
    #[cfg(feature = "auth")]
    pub use super::auth::AuthorizedBearer;
    #[cfg(feature = "auth")]
    pub use super::auth::AuthorizedBearerWithClaims;
    #[cfg(feature = "auth")]
    pub use super::auth::AuthorizedBearerWithRole;
    #[cfg(feature = "auth")]
    pub use super::auth::AuthorizedCookie;
    #[cfg(feature = "auth")]
    pub use super::auth::AuthorizedCookieWithClaims;
    #[cfg(feature = "auth")]
    pub use super::auth::AuthorizedCookieWithRole;
    #[cfg(feature = "auth")]
    pub use super::auth::BearerClaims;
    #[cfg(feature = "auth")]
    pub use super::auth::BearerToken;
    #[cfg(feature = "auth")]
    pub use super::auth::CookieClaims;
    #[cfg(feature = "auth")]
    pub use super::auth::CookieToken;
    #[cfg(feature = "auth")]
    pub use super::auth::jwt::JWT;
    #[cfg(feature = "auth")]
    pub use super::auth::jwt::VerifiedClaims;
    #[cfg(feature = "auth")]
    pub use super::auth::jwt::claims_for;
    #[cfg(feature = "auth")]
    pub use axum_extra::extract::CookieJar;
    #[cfg(feature = "auth")]
    pub use jsonwebtoken::DecodingKey;

    #[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
    #[cfg(feature = "login")]
    pub use super::auth::login::login_cookie;
    #[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
    #[cfg(feature = "login")]
    pub use super::auth::login::login_setup;
    #[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
    #[cfg(feature = "login")]
    pub use super::auth::login::login_token;
    #[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
    #[cfg(feature = "login")]
    pub use super::auth::login::logout_cookie;
    #[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
    #[cfg(feature = "login")]
    pub use super::auth::login::register_user;
    #[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
    #[cfg(feature = "login")]
    pub use super::auth::login::register_user_confirm;
}