# Axum Starter

[![Github](https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github)](https://github.com/Goodjooy/axum-server-starter)
[![Crates.io](https://img.shields.io/crates/v/axum-starter.svg?style=for-the-badge)](https://crates.io/crates/axum-starter)
![License](https://img.shields.io/github/license/Goodjooy/axum-server-starter?style=for-the-badge)

## Why axum-starter

With the growing of the server functions, the code which prepare multiply infrastructures for the server in the main become more and more complex.  
For example, I need connect to `Mysql` and `Redis`, start `MessageQuery` , start GracefulShutdown and so on.  
In other to simplify the start up code with my server project, there comes the `axum-starter`

## Safety

the outer attribute `#![forbid(unsafe_code)]` enable

## Simple Example

The following example using `axum-starter` starting a web server which
server on `http://127.0.0.1:5050`

It can do

1. show info before launch (with `logger` feature)
2. using `simple_logger` and adding TraceLayer as logger middleware
3. request `http://127.0.0.1:5050/greet/{name}` will respond greet with your name

```rust
use axum::{extract::Path, routing::get};
use axum_starter::{prepare, router::Route, ServerPrepare};
use config::Conf;
use tower_http::trace::TraceLayer;

#[tokio::main]
async fn main() {
    start().await;
}

async fn start() {
    ServerPrepare::with_config(Conf::default())
        .init_logger()
        .expect("Init Logger Error")
        .prepare_route(GreetRoute)
        .layer(TraceLayer::new_for_http())
        .no_state()
        .prepare_start()
        .await
        .expect("Prepare for Start Error")
        .launch()
        .await
        .expect("Server Error");
}

mod config {
    use std::net::Ipv4Addr;

    use axum_starter::{Configure, Provider};
    use log::LevelFilter;
    use log::SetLoggerError;
    use simple_logger::SimpleLogger;

    // prepare the init configure
    #[derive(Debug, Default, Provider, Configure)]
    #[conf(
        address(func(
            path = "||(Ipv4Addr::LOCALHOST, 5050)",
            ty = "(Ipv4Addr, u16)",
            associate,
        )),
        logger(
            func = "||SimpleLogger::new().with_level(LevelFilter::Debug).init()",
            error = "SetLoggerError",
            associate,
        ),
        server
    )]
    pub(super) struct Conf {}
}

async fn greet(Path(name): Path<String>) -> String {
    format!("Welcome {name} !")
}

#[prepare(GreetRoute)]
fn greet_route<S, B>() -> Route<S, B>
where
    B: http_body::Body + Send + 'static,
    S: Clone + Send + Sync + 'static,
{
    Route::new("/greet/:name", get(greet))
}
```

## Core Concept

Each task before starting the server call [`Prepare`](https://docs.rs/axum-starter/latest/axum_starter/trait.Prepare.html). Each `Prepare` will Return a `PreparedEffect` for `ServerPrepare` to apply each prepare's effect on the server.
Finally, all `Prepare` are done and the server can be launch

### [`Prepare`](https://docs.rs/axum-starter/latest/axum_starter/trait.Prepare.html) trait

the trait define the prepare task,
after prepare down, it return a `PreparedEffect`

### `PreparedEffect` trait family

the trait family will apply multiply effect on the server. include the following

- [Router](https://docs.rs/axum-starter/latest/axum_starter/trait.PrepareRouteEffect.html)
- [State](https://docs.rs/axum-starter/latest/axum_starter/trait.PrepareStateEffect.html)
- [Middleware](https://docs.rs/axum-starter/latest/axum_starter/trait.PrepareMiddlewareEffect.html)

## `Concurrently` or `Serially`

`Prepare`s will run one by one in default, in another word, they running _serially_,
if you want run some `Prepare`s _concurrently_, you can call [`ServerPrepare::prepare_concurrent`](https://docs.rs/axum-starter/latest/axum_starter/struct.ServerPrepare.html#method.prepare_concurrent), to give a group of `Prepare`s running _concurrently_

## Set Middleware

if you want to adding a middleware on the root of server `Router`, using [`ServerPrepare::layer`](crate::ServerPrepare::layer) then giving the `Layer`

or using [`PrepareMiddlewareEffect`](crate::PrepareMiddlewareEffect) apply middleware in [`Prepare`](crate::Prepare)