Skip to content

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:

Terminal window
nestforge new my-api --openapi

That scaffold enables the required feature flag and wires the docs routes into the generated bootstrap so you can start from a working OpenAPI project.

First, add the openapi feature to your nestforge dependency in Cargo.toml:

[dependencies]
nestforge = { version = "1", features = ["openapi"] }

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.

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()))
}
}
  1. Run your application: cargo run
  2. Access the OpenAPI JSON: http://localhost:3000/api/openapi.json
  3. Access the Documentation UI: http://localhost:3000/api/docs

If you also enable .with_version("v1"), those routes would be mounted under /api/v1/....

Use #[nestforge::tag("Name")] at the method level to group routes in the UI.

You can specify multiple #[nestforge::response(...)] attributes to document different status codes and their meanings.

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> {
// ...
}
  • “Cannot find attribute summary”: Ensure the openapi feature is enabled in Cargo.toml.
  • “Trait bound NestForgeFactory<...>: NestForgeFactoryOpenApiExt<...> not satisfied”: Make sure you have use nestforge::NestForgeFactoryOpenApiExt; in your imports.
  • Routes missing from docs: Ensure the controller is registered in your AppModule.