[![crates.io](https://img.shields.io/crates/v/spring-web.svg)](https://crates.io/crates/spring-web) [![Documentation](https://docs.rs/spring-web/badge.svg)](https://docs.rs/spring-web) [Axum](https://github.com/tokio-rs/axum) is one of the best web frameworks in the Rust community. It is a sub-project based on [hyper](https://github.com/hyperium/hyper) maintained by Tokio. Axum provides web routing, declarative HTTP request parsing, HTTP response serialization, and can be combined with the middleware in the [tower](https://github.com/tower-rs) ecosystem. ## Dependencies ```toml spring-web = { version = "" } ``` optional **features**: `http2`, `multipart`, `ws`. ## Configuration items ```toml [web] binding = "172.20.10.4" # IP address of the network card to bind, default 0.0.0.0 port = 8000 # Port number to bind, default 8080 connect_info = false # Whether to use client connection information, default false graceful = true # Whether to enable graceful shutdown, default false # Web middleware configuration [web.middlewares] compression = { enable = true } # Enable compression middleware catch_panic = { enable = true } # Capture panic generated by handler logger = { enable = true, level = "info" } # Enable log middleware limit_payload = { enable = true, body_limit = "5MB" } # Limit request body size timeout_request = { enable = true, timeout = 60000 } # Request timeout 60s # Cross-domain configuration cors = { enable = true, allow_origins = [ "*.github.io", ], allow_headers = [ "Authentication", ], allow_methods = [ "GET", "POST", ], max_age = 60 } # Static resource configuration static = { enable = true, uri = "/static", path = "static", precompressed = true, fallback = "index.html" } ``` > **NOTE**: The above middleware configuration can integrate the middleware provided in the tower ecosystem. Of course, if you are very familiar with the tower ecosystem, you can also configure it yourself by writing code without enabling these middleware. The following are relevant document links: > * [tower](https://docs.rs/tower/latest/tower/) > * [tower-http](https://docs.rs/tower-http/latest/tower_http/) ## API interface App implements the [WebConfigurator](https://docs.rs/spring-web/latest/spring_web/trait.WebConfigurator.html) feature, which can be used to specify routing configuration: ```no_run, rust, linenos, hl_lines=6 10-18 use spring::App; use spring_web::get; use spring_web::{WebPlugin, WebConfigurator, Router, axum::response::IntoResponse, handler::TypeRouter}; use spring_sqlx::SqlxPlugin; #[tokio::main] async fn main() { App::new() .add_plugin(SqlxPlugin) .add_plugin(WebPlugin) .add_router(router()) .run() .await } fn router() -> Router { Router::new().typed_route(hello_word) } #[get("/")] async fn hello_word() -> impl IntoResponse { "hello word" } ``` You can also use the `auto_config` macro to implement automatic configuration. This process macro will automatically register the routes marked by the Procedural Macro into the app: ```diff +#[auto_config(WebConfigurator)] #[tokio::main] async fn main() { App::new() .add_plugin(SqlxPlugin) .add_plugin(WebPlugin) - .add_router(router()) .run() .await } -fn router() -> Router { - Router::new().typed_route(hello_word) -} ``` ## Attribute macro [`get`](https://docs.rs/spring-macros/latest/spring_macros/attr.get.html) in the above example is an attribute macro. `spring-web` provides eight standard HTTP METHOD process macros: `get`, `post`, `patch`, `put`, `delete`, `head`, `trace`, `options`. You can also use the [`route`](https://docs.rs/spring-macros/latest/spring_macros/attr.route.html) macro to bind multiple methods at the same time: ```rust use spring_web::route; use spring_web::axum::response::IntoResponse; #[route("/test", method = "GET", method = "HEAD")] async fn example() -> impl IntoResponse { "hello world" } ``` In addition, spring also supports binding multiple routes to a handler, which requires the [`routes`](https://docs.rs/spring-macros/latest/spring_macros/attr.routes.html) attribute macro: ```rust use spring_web::{routes, get, delete}; use spring_web::axum::response::IntoResponse; #[routes] #[get("/test")] #[get("/test2")] #[delete("/test")] async fn example() -> impl IntoResponse { "hello world" } ``` ## Extract the Component registered by the plugin In the above example, the `SqlxPlugin` plugin automatically registers a Sqlx connection pool component for us. We can use `Component` to extract this connection pool from State. [`Component`](https://docs.rs/spring-web/latest/spring_web/extractor/struct.Component.html) is an axum [extractor](https://docs.rs/axum/latest/axum/extract/index.html). ```rust use anyhow::Context; use spring_web::get; use spring_web::{axum::response::IntoResponse, extractor::Component, error::Result}; use spring_sqlx::{ConnectPool, sqlx::{self, Row}}; #[get("/version")] async fn mysql_version(Component(pool): Component) -> Result { let version = sqlx::query("select version() as version") .fetch_one(&pool) .await .context("sqlx query failed")? .get("version"); Ok(version) } ``` Axum also provides other [extractors](https://docs.rs/axum/latest/axum/extract/index.html), which are reexported under [`spring_web::extractor`](https://docs.rs/spring-web/latest/spring_web/extractor/index.html). ## Read configuration You can use [`Config`](https://docs.rs/spring-web/latest/spring_web/extractor/struct.Config.html) to extract the configuration in the toml file. ```rust use spring_web::get; use spring_web::{extractor::Config, axum::response::IntoResponse}; use spring::config::Configurable; use serde::Deserialize; #[derive(Debug, Configurable, Deserialize)] #[config_prefix = "custom"] struct CustomConfig { a: u32, b: bool, } #[get("/config")] async fn use_toml_config(Config(conf): Config) -> impl IntoResponse { format!("a={}, b={}", conf.a, conf.b) } ``` Add the corresponding configuration to your configuration file: ```toml [custom] a = 1 b = true ``` Complete code reference [`web-example`][web-example] [web-example]: https://github.com/spring-rs/spring-rs/tree/master/examples/web-example ## Use Extractor in Middleware You can also use [Extractor in middleware](https://docs.rs/axum/latest/axum/middleware/fn.from_fn.html), but please note that you need to follow the rules of axum. ```rust use spring_web::{axum::{response::Response, middleware::Next}, extractor::{Request, Component}}; use spring_sqlx::ConnectPool; async fn problem_middleware(Component(db): Component, request: Request, next: Next) -> Response { // do something let response = next.run(request).await; response } ``` Complete code reference [`web-middleware-example`][web-middleware-example] [web-middleware-example]: https://github.com/spring-rs/spring-rs/tree/master/examples/web-middleware-example