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 dependenciesEntry Point
The main.rs file bootstraps the application, configures middleware, and starts the server:
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:
| Endpoint | Purpose | Response |
|---|---|---|
/health | Liveness probe (server is up) | 200 OK |
/ready | Readiness probe (DB is connected) | 200 OK or 503 |
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:
PORT=3000 cargo runRequest Lifecycle
Every request flows through a predictable pipeline:
- CORS middleware validates the request origin
- Request ID middleware assigns a unique
X-Request-Idheader - Route matching dispatches to the appropriate handler
- Auth middleware (on protected routes) validates the JWT token
- RBAC middleware (on admin routes) checks user permissions
- Handler parses the request and delegates to a service
- Service executes business logic and queries the database
- Response is serialized as JSON and returned
What's Next
- Authentication — JWT-based auth with access and refresh tokens
- Authorization — Role-based access control (RBAC)
- Database — PostgreSQL schema, migrations, and seeders
- Models — Database models and query patterns
- Handlers — Request handler conventions
- Services — Business logic layer
- Middleware — Auth, RBAC, and request pipeline
- Routes — Route registration and grouping
- DTOs — Request/response type definitions
- Error Handling — Structured error responses
- API Documentation — OpenAPI/Swagger generation