Architecture
The high-level mental model behind NestForge and its request lifecycle.
NestForge is designed to be a platform-agnostic framework. While its primary use case is building HTTP APIs, its core architecture is decoupled from any specific transport. This allows NestForge patterns to be applied to GraphQL, gRPC, and even custom message buses.
The Three Layers
Section titled “The Three Layers”The NestForge ecosystem is organized into three distinct layers:
- Core Layer (
nestforge-core): The brain of the framework. It handles the Module graph, Dependency Injection, Validation, and internal Pipeline abstractions. It has no knowledge of HTTP or Axum. - Runtime Layer (
nestforge-http): The bridge to the world. It takes the Core model and mounts it onto a web server (Axum/Tokio). - Transport Layer: Optional extensions for other protocols like
nestforge-graphql,nestforge-grpc, andnestforge-websockets.
Request Lifecycle
Section titled “Request Lifecycle”Understanding how a request moves through NestForge is crucial for debugging and designing efficient applications. Below is the sequence of events from when a request hits the server to when the response is sent back.
sequenceDiagram participant Client participant Middleware as Middleware (Axum Layer) participant Guards as Guards participant Interceptors_Pre as Interceptors (Pre) participant Handler as Route Handler (Controller) participant Interceptors_Post as Interceptors (Post) participant ExceptionFilters as Exception Filters
Client->>Middleware: HTTP Request Middleware->>Guards: Extract Context & Run Guards alt Unauthorized Guards-->>Client: 403 Forbidden / 401 Unauthorized else Authorized Guards->>Interceptors_Pre: Initialize Interceptor Chain Interceptors_Pre->>Handler: Execute Handler (DI Resolution) alt Success Handler->>Interceptors_Post: Map Response Interceptors_Post->>Client: HTTP Response else Error Handler->>ExceptionFilters: Catch Error ExceptionFilters->>Client: Formatted Error Response end end1. Middleware
Section titled “1. Middleware”Middleware is the first line of defense. In NestForge, these are standard Axum/Tower middlewares. They are perfect for low-level concerns like logging, CORS, or compression.
2. Guards
Section titled “2. Guards”Guards have a single responsibility: determine whether a request should be handled by the route handler or not, based on certain conditions (e.g., roles, permissions).
3. Interceptors
Section titled “3. Interceptors”Interceptors are powerful tools that allow you to:
- Bind extra logic before/after method execution.
- Transform the result returned from a function.
- Transform the exception thrown from a function.
- Extend basic function behavior.
4. Route Handler
Section titled “4. Route Handler”This is where your business logic lives. Handlers use Dependency Injection to resolve the services they need to fulfill the request.
Dependency Injection (DI)
Section titled “Dependency Injection (DI)”NestForge features a robust DI system. Unlike many Rust frameworks that rely on global state, NestForge creates a scoped container for every request.
- Singleton Providers: Created once and shared across the entire application lifetime.
- Request Providers: Created once per request. Perfect for services that need to know about the current user or request ID.
- Transient Providers: A new instance is created every time it is injected.
// A service is just a struct registered as a providerpub struct UsersService { db: Inject<Db>,}
#[routes]impl UsersController { // UsersService is automatically resolved from the container async fn get(users: Inject<UsersService>) -> ApiResult<UserDto> { ... }}Platform Independence
Section titled “Platform Independence”The “Secret Sauce” of NestForge is that the Module Graph is resolved independently of the transport. This means you can write a service once and inject it into an HTTP Controller, a GraphQL Resolver, AND a gRPC Service simultaneously.