OpenAPI from Scratch
A complete guide to setting up OpenAPI documentation in a new NestForge project.
This guide walks you through enabling and configuring automatic OpenAPI documentation generation for your NestForge project.
If you want the CLI to scaffold the OpenAPI setup for you, start with:
nestforge new my-api --openapiThat scaffold enables the required feature flag and wires the docs routes into the generated bootstrap so you can start from a working OpenAPI project.
Step 1: Enable the Feature
Section titled “Step 1: Enable the Feature”First, add the openapi feature to your nestforge dependency in Cargo.toml:
[dependencies]nestforge = { version = "1", features = ["openapi"] }Step 2: Configure the App Factory
Section titled “Step 2: Configure the App Factory”In your src/main.rs, use the with_openapi_docs extension method to enable the documentation routes.
use nestforge::{NestForgeFactory, NestForgeFactoryOpenApiExt};use crate::app_module::AppModule;
#[tokio::main]async fn main() -> anyhow::Result<()> { NestForgeFactory::<AppModule>::create()? .with_global_prefix("api") // This adds /openapi.json and /docs routes .with_openapi_docs("My API Title", "1.0.0")? .listen(3000) .await?; Ok(())}If you also use .with_version("v1"), the generated docs routes will follow the
same prefixed application structure.
Step 3: Document your Controllers
Section titled “Step 3: Document your Controllers”Add metadata to your controller routes using nestforge attributes. These will be automatically picked up by the documentation generator.
use nestforge::{controller, routes, ApiResult};use axum::Json;
#[controller("/users")]pub struct UsersController;
#[routes]impl UsersController { #[nestforge::get("/")] #[nestforge::summary("List all users")] #[nestforge::tag("Users")] #[nestforge::response(status = 200, description = "List of users successfully retrieved")] async fn list_users() -> ApiResult<Vec<String>> { Ok(Json(vec!["Alice".to_string(), "Bob".to_string()])) }
#[nestforge::get("/{id}")] #[nestforge::summary("Get a user by ID")] #[nestforge::tag("Users")] #[nestforge::response(status = 200, description = "User found")] #[nestforge::response(status = 404, description = "User not found")] async fn get_user(id: nestforge::Param<u64>) -> ApiResult<String> { Ok(Json("Alice".to_string())) }}Step 4: Verify the Documentation
Section titled “Step 4: Verify the Documentation”- Run your application:
cargo run - Access the OpenAPI JSON: http://localhost:3000/api/openapi.json
- Access the Documentation UI: http://localhost:3000/api/docs
If you also enable .with_version("v1"), those routes would be mounted under
/api/v1/....
Advanced Configuration
Section titled “Advanced Configuration”Grouping and Tags
Section titled “Grouping and Tags”Use #[nestforge::tag("Name")] at the method level to group routes in the UI.
Custom Responses
Section titled “Custom Responses”You can specify multiple #[nestforge::response(...)] attributes to document different status codes and their meanings.
Authentication Documentation
Section titled “Authentication Documentation”If a route is marked with #[nestforge::authenticated], the generated OpenAPI spec will automatically include the required security schemes (Bearer Auth by default).
#[nestforge::get("/me")]#[nestforge::authenticated]#[nestforge::summary("Get current user")]async fn me() -> ApiResult<String> { // ...}Troubleshooting
Section titled “Troubleshooting”- “Cannot find attribute
summary”: Ensure theopenapifeature is enabled inCargo.toml. - “Trait bound
NestForgeFactory<...>: NestForgeFactoryOpenApiExt<...>not satisfied”: Make sure you haveuse nestforge::NestForgeFactoryOpenApiExt;in your imports. - Routes missing from docs: Ensure the controller is registered in your
AppModule.