Skip to content

Backend Overview

FORGE generates a production-ready REST API built on Axum, Rust's leading async web framework. The generated backend follows a layered architecture that separates concerns cleanly, making your codebase maintainable as it grows from a simple CRUD API to a full-featured application.

Architecture

The generated API follows a strict layered architecture where each layer has a single responsibility:

┌─────────────────────────────────────────────┐
│              HTTP Request                    │
├─────────────────────────────────────────────┤
│           Middleware Layer                   │
│    (Auth, RBAC, Request ID, CORS)           │
├─────────────────────────────────────────────┤
│           Handler Layer                      │
│    (Request parsing, response building)      │
├─────────────────────────────────────────────┤
│           Service Layer                      │
│    (Business logic, validation)              │
├─────────────────────────────────────────────┤
│           Model Layer                        │
│    (Database queries, data mapping)          │
├─────────────────────────────────────────────┤
│           PostgreSQL Database                │
└─────────────────────────────────────────────┘

Data flows downward through the layers: a handler receives the HTTP request, delegates business logic to a service, which in turn queries the database through models. Responses flow back up.

TIP

Each layer only communicates with its immediate neighbor. Handlers never access the database directly, and services never construct HTTP responses.

Project Structure

api/
├── src/
│   ├── main.rs              # Entry point, router setup, middleware registration
│   ├── config/
│   │   ├── mod.rs            # Configuration module
│   │   ├── app.rs            # Application settings (port, environment, secrets)
│   │   └── database.rs       # Database connection pool configuration
│   ├── handlers/
│   │   ├── mod.rs            # Handler module exports
│   │   ├── auth.rs           # Authentication endpoints
│   │   ├── profile.rs        # User profile endpoints
│   │   └── admin/
│   │       ├── mod.rs        # Admin handler exports
│   │       ├── users.rs      # User management (CRUD)
│   │       ├── roles.rs      # Role management
│   │       ├── contents.rs   # Content management
│   │       └── settings.rs   # Application settings
│   ├── models/
│   │   ├── mod.rs            # Model module exports
│   │   ├── user.rs           # User model and queries
│   │   ├── role.rs           # Role model
│   │   ├── permission.rs     # Permission model
│   │   └── content.rs        # Content model (translatable)
│   ├── dto/
│   │   ├── mod.rs            # DTO module exports
│   │   ├── common.rs         # Shared types (ApiResponse, Pagination)
│   │   ├── auth.rs           # Auth request/response types
│   │   ├── user.rs           # User DTOs
│   │   └── content.rs        # Content DTOs
│   ├── services/
│   │   ├── mod.rs            # Service module exports
│   │   ├── auth.rs           # Authentication logic
│   │   ├── user.rs           # User business logic
│   │   └── content.rs        # Content business logic
│   ├── middleware/
│   │   ├── mod.rs            # Middleware module exports
│   │   ├── auth.rs           # JWT authentication middleware
│   │   ├── rbac.rs           # Permission checking middleware
│   │   └── request_id.rs     # Request ID generation
│   ├── routes/
│   │   ├── mod.rs            # Route module exports
│   │   ├── admin.rs          # Admin route registration (/api/admin/*)
│   │   └── public.rs         # Public route registration (/api/*)
│   └── utils/
│       ├── mod.rs            # Utility module exports
│       ├── response.rs       # Response builder helpers
│       └── pagination.rs     # Pagination utilities
├── database/
│   ├── migrations/           # Sequential SQL migrations
│   └── seeders/              # Seed data (roles, permissions, admin user)
├── .env                      # Environment variables
└── Cargo.toml                # Rust dependencies

Entry Point

The main.rs file bootstraps the application, configures middleware, and starts the server:

rust
use axum::{Router, middleware};
use tower_http::cors::CorsLayer;
use std::net::SocketAddr;

#[tokio::main]
async fn main() {
    // Initialize tracing
    tracing_subscriber::init();

    // Load configuration
    let config = config::AppConfig::from_env();

    // Create database pool
    let pool = config::database::create_pool(&config.database_url).await;

    // Run pending migrations
    sqlx::migrate!("./database/migrations")
        .run(&pool)
        .await
        .expect("Failed to run migrations");

    // Build application router
    let app = Router::new()
        .nest("/api/admin", routes::admin::routes(pool.clone()))
        .nest("/api", routes::public::routes(pool.clone()))
        .route("/health", axum::routing::get(|| async { "OK" }))
        .route("/ready", axum::routing::get(health_check))
        .layer(CorsLayer::permissive())
        .layer(middleware::from_fn(middleware::request_id::add_request_id));

    // Start server
    let addr = SocketAddr::from(([0, 0, 0, 0], config.port));
    tracing::info!("Server listening on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

Health Checks

The generated API exposes two health endpoints:

EndpointPurposeResponse
/healthLiveness probe (server is up)200 OK
/readyReadiness probe (DB is connected)200 OK or 503
rust
async fn health_check(
    State(pool): State<PgPool>,
) -> impl IntoResponse {
    match sqlx::query("SELECT 1")
        .execute(&pool)
        .await
    {
        Ok(_) => (StatusCode::OK, "Ready"),
        Err(_) => (StatusCode::SERVICE_UNAVAILABLE, "Not Ready"),
    }
}

WARNING

The /ready endpoint checks database connectivity. Use it for Kubernetes readiness probes or load balancer health checks. The /health endpoint is a simple liveness check that always returns 200 if the server process is running.

Default Port

The API runs on port 8080 by default. Configure it via the PORT environment variable:

bash
PORT=3000 cargo run

Request Lifecycle

Every request flows through a predictable pipeline:

  1. CORS middleware validates the request origin
  2. Request ID middleware assigns a unique X-Request-Id header
  3. Route matching dispatches to the appropriate handler
  4. Auth middleware (on protected routes) validates the JWT token
  5. RBAC middleware (on admin routes) checks user permissions
  6. Handler parses the request and delegates to a service
  7. Service executes business logic and queries the database
  8. Response is serialized as JSON and returned

What's Next

Released under the MIT License.