Skip to content

Latest commit

Β 

History

History
319 lines (242 loc) Β· 8.73 KB

File metadata and controls

319 lines (242 loc) Β· 8.73 KB

Miko

A modern, high-performance Rust web framework

Crates.io Documentation License: MIT

δΈ­ζ–‡ | English

✨ Features

  • πŸš€ High Performance - Built on Hyper and Tokio, fully leveraging Rust's asynchronous features.
  • 🎯 Type Safe - Complete type inference, catching errors at compile time.
  • πŸ”Œ Modular Design - Enable features on demand via features.
  • 🎨 Elegant Macros - Provides concise and intuitive route definition macros.
  • πŸ”„ Dependency Injection - Built-in dependency container, supporting automatic component assembly.
  • πŸ“ OpenAPI Support - Seamless integration with utoipa for automatic API documentation generation.
  • βœ… Data Validation - Integrated with garde for powerful data validation capabilities.
  • 🌐 WebSocket - Native WebSocket support.
  • βœ… Built-in Testing - Powerful TestClient for lightning-fast in-process integration testing.
  • πŸ” Unified Error Handling - Elegant error handling mechanism.
  • πŸ”„ Graceful Shutdown - Signal handling and connection draining.
  • 🎭 Tower Ecosystem - Compatible with the Tower middleware ecosystem.

πŸš€ Quick Start

Installation

cargo add miko --features=full

Hello World

use miko::*;
use miko::macros::*;

#[get("/")]
async fn hello() -> &'static str {
    "Hello, Miko!"
}

#[miko]
async fn main() {
}

After running the program, visit http://localhost:8080.

More Examples

use miko::{*, macros::*, extractor::{Json, Path, Query}};
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct CreateUser {
    name: String,
    email: String,
}

#[derive(Serialize)]
struct User {
    id: u32,
    name: String,
    email: String,
}

// Using route macros and extractors
#[post("/users")]
async fn create_user(Json(data): Json<CreateUser>) -> Json<User> {
    Json(User {
        id: 1,
        name: data.name,
        email: data.email,
    })
}

// Path parameters
#[get("/users/{id}")]
async fn get_user(Path(id): Path<u32>) -> Json<User> {
    Json(User {
        id,
        name: "Alice".into(),
        email: "alice@example.com".into(),
    })
}
// Query parameters
#[derive(Debug, Deserialize)]
struct SearchQuery {
    q: Option<String>,
    page: Option<u32>,
    per_page: Option<u32>,
}

#[get("/search")]
async fn search(Query(params): Query<SearchQuery>) -> String {
    format!("Searching for: {:?}", params)
}
#[tokio::main]
async fn main() {
    let router = Router::new()
        .post("/users", create_user)
        .get("/users/{id}", get_user)
        .get("/search", search);

    Application::new_(router).run().await.unwrap();
}

πŸ“š Documentation

🎯 Features

Miko has a modular design, allowing you to enable features as needed:

[dependencies]
# By default, core features are enabled (macros, auto-registration, extensions)
miko = "x.x"

# Or enable all features, including OpenAPI and data validation
miko = { version = "x.x", features = ["full"] }

# Or enable only the features you need
miko = { version = "x.x", features = ["utoipa", "validation"] }

Available features:

  • default - Core features (macro + auto + ext), enabled by default
  • full - Enables all features (including external extensions)
  • macro - Enables route macros (#[get], #[post], etc.)
  • auto - Enables automatic route registration and dependency injection
  • ext - Enables extension features (quick CORS, static files, etc.)
  • test - Enables integration testing tools (TestClient)
  • utoipa - Enables OpenAPI documentation generation (automatically re-exports the utoipa crate)
  • validation - Enables data validation (automatically re-exports the garde crate)

Note: When the utoipa or validation feature is enabled, you don't need to manually add these dependencies to your Cargo.toml. The framework automatically re-exports them:

// After enabling the utoipa feature, use it directly
use miko::{utoipa, OpenApi, ToSchema};

// After enabling the validation feature, use it directly
use miko::{garde, Validate};

πŸ› οΈ Core Components

Route Macros

Define routes with concise macros:

#[get("/users")]
async fn list_users() -> Json<Vec<User>> { /* ... */ }

#[post("/users")]
async fn create_user(Json(data): Json<CreateUser>) -> AppResult<Json<User>> { /* ... */ }

#[put("/users/{id}")]
async fn update_user(Path(id): Path<u32>, Json(data): Json<UpdateUser>) -> AppResult<Json<User>> { /* ... */ }

#[delete("/users/{id}")]
async fn delete_user(Path(id): Path<u32>) -> AppResult<()> { /* ... */ }

Dependency Injection

Use #[component] and #[dep] for dependency injection:

#[component]
impl Database {
    async fn new() -> Self {
        // Initialize database connection
        Self { /* ... */ }
    }
}

#[get("/users")]
async fn list_users(#[dep] db: Arc<Database>) -> Json<Vec<User>> {
    // Use the injected database instance
    Json(vec![])
}

Declarative Middleware

Define reusable middleware using #[middleware], supporting argument injection:

#[middleware]
async fn logger(#[config("app.name")] app_name: String) -> AppResult<Resp> {
    println!("Request to {}", app_name);
    _next.run(_req).await
}

#[get("/")]
#[layer(logger())]
async fn hello() -> &'static str {
    "Hello"
}

OpenAPI Documentation

Automatically generate API documentation with inferred params, summary, and description. When utoipa + auto are enabled, AutoPaths can collect macro routes so you do not need to maintain paths(...) manually.

use miko::*;
use miko::openapi::AutoPaths;

#[derive(OpenApi)]
#[openapi(
    info(title = "Miko Basic Example API", version = "1.0.0"),
    modifiers(&AutoPaths)
)]
struct ApiDoc;

#[derive(Serialize, Deserialize, ToSchema)]
struct User {
    id: u32,
    name: String,
}

#[get("/users/{id}")]
#[u_tag("User Management")]
#[u_response(status = 200, description = "Success", body = User)]
async fn get_user(
    #[path] #[desc("User ID")] id: u32
) -> Json<User> {
    // ...
}

Data Validation

Use ValidatedJson for automatic validation:

use garde::Validate;

#[derive(Deserialize, Validate)]
struct CreateUser {
    #[garde(length(min = 3, max = 50))]
    name: String,

    #[garde(contains("@"))]
    email: String,
}

#[post("/users")]
async fn create_user(
    ValidatedJson(data): ValidatedJson<CreateUser>
) -> Json<User> {
    // Data has been validated
}

🌟 Example

The miko/examples/ directory contains a comprehensive all-in-one example:

This example covers most of the framework's core features, including routing, middleware, dependency injection, WebSockets, file uploads, and more. It is highly recommended to check this file to quickly understand how to use Miko.

To run the example:

cargo run --example basic --features full

🀝 Contributing

We welcome contributions of any kind. For details on how to contribute, please see CONTRIBUTING.md.

πŸ“„ License

πŸ”— Related Links

πŸ’¬ Community & Support