/clean-axum

Axum scaffold with clean architecture

Primary LanguageRustMIT LicenseMIT

clean-axum

Axum scaffold with clean architecture.

You probably don't need Rust on Rails.

Refer to this post for rationale and background.

Features

  • Axum framework
  • SeaORM domain models
  • Completely separated API routers and DB-related logic (named "persistence" layer)
  • Completely separated input parameters, queries and output schemas
  • OpenAPI documentation (Swagger UI and Scalar) powered by Utoipa
  • Error handling with Anyhow
  • Custom parameter validation with validator
  • Optional Shuttle runtime
  • Optional prefork workers for maximizing performance on Linux

Module hierarchy

API logic

  • api::routers: Axum endpoints
  • api::error: Models and traits for error handling
  • api::extractor Custom Axum extractors
    • api::extractor::json: Json for bodies and responses
    • api::extractor::valid: Valid for JSON body validation
  • api::validation: JSON validation model based on validator
  • api::models: Non domain model API models
    • api::models::response: JSON error response

OpenAPI documentation

  • doc: Utoipa doc declaration

API-agonistic application logic

Main concept: Web framework is replaceable.

All modules here should not include any specific API web framework logic.

  • app::persistence: DB manipulation (CRUD) functions
  • app::config: DB or API server configuration
  • app::state: APP state, e.g. DB connection
  • app::error: APP errors used by api::error. e.g. "User not found"

DB/API-agnostic domain models

Main concept: Database (Sqlite/MySQL/PostgreSQL) is replaceable.

Except models::domains and migration, all modules are ORM library agnostic.

  • models::domains: SeaORM domain models
  • models::params: Serde input parameters for creating/updating domain models in DB
  • models::schemas: Serde output schemas for combining different domain models
  • models::queries: Serde queries for filtering domain models
  • migration: SeaORM migration files

Unit and integration tests

  • tests::api: API integration tests. Hierarchy is the same as api::routers
  • tests::app::persistence: DB/ORM-related unit tests. Hierarchy is the same as app::persistence

Others

  • utils: Utility functions
  • main: Tokio and Shuttle conditional entry point

Run

Start server

cp .env.example .env
# touch dev.db
# cargo install sea-orm-cli
# sea-orm-cli migrate up
cargo run

# or for production
cargo run --release

Call API

curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d '{"username":"aaa"}'
curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d '{"username":"abc"}'
curl http://localhost:3000/users\?username\=a

OpenAPI doc (Swagger UI/Scalar)

open http://localhost:3000/docs
open http://localhost:3000/scalar

Start Shuttle local server

# cargo install cargo-shuttle
cargo shuttle run

Make sure docker engine is running, otherwise:

brew install colima docker
colima start
sudo ln -sf $HOME/.colima/default/docker.sock /var/run/docker.sock

Shuttle deployment

cargo shuttle login
cargo shuttle deploy

Benchmark

# edit .env to use Postgres
cargo run --release
wrk --latency -t20 -c50 -d10s http://localhost:3000/users\?username\=