rovo
A drop-in replacement for axum's Router that adds automatic OpenAPI documentation using doc comments.
Built on top of aide, rovo provides a seamless way to document your axum APIs without writing separate documentation functions.
Features
- ðŊ Drop-in replacement: Use
rovo::Routerinstead ofaxum::Routerwith the exact same API - ð Doc-comment driven: Write API docs as Rust doc comments with special annotations
- â Compile-time validation: Catches documentation errors at compile time, not runtime
- ð Method chaining: Supports
.post(),.patch(),.delete()just like axum - ð Simplified setup: Helper methods for Swagger UI and OpenAPI JSON endpoints
- ð·ïļ Rich annotations: Support for tags, security, deprecation, examples, and more
- ⥠Type-safe: Full type checking for response types and examples
- ðŠķ Lightweight: Minimal overhead over plain axum
Installation
[]
= { = "0.1", = ["swagger"] } # Choose your UI: swagger, redoc, or scalar
= { = "0.15", = ["axum"] }
= "0.8"
= "0.8"
= { = "1.0", = ["derive"] }
Feature Flags
Rovo supports multiple OpenAPI documentation UIs through feature flags. Note: No UI is enabled by default - you must explicitly choose which UI(s) to use:
swagger- Enables Swagger UI supportredoc- Enables Redoc UI supportscalar- Enables Scalar UI support
You can enable one or multiple UIs:
[]
# Use Swagger UI
= { = "0.1", = ["swagger"] }
# Use Redoc
= { = "0.1", = ["redoc"] }
# Use Scalar
= { = "0.1", = ["scalar"] }
# Use all three UIs
= { = "0.1", = ["swagger", "redoc", "scalar"] }
Quick Start
use IntoApiResponse;
use OpenApi;
use ;
use ;
use JsonSchema;
use Serialize;
/// Get user information.
///
/// Returns the current user's profile information.
///
/// @tag users
/// @response 200 Json<User> User profile retrieved successfully.
async
async
async
Visit http://127.0.0.1:3000 to see your interactive Swagger UI documentation!
Documentation Annotations
Basic Structure
/// Title (first line becomes the summary)
///
/// Description paragraph can span multiple lines
/// and provides detailed information about the endpoint.
///
/// @tag category_name
/// @response 200 Json<ResponseType> Success description
/// @response 404 () Not found description
async
Available Annotations
@response <code> <type> <description>
Document response status codes:
/// @response 200 Json<User> User found successfully
/// @response 404 () User not found
/// @response 500 Json<ErrorResponse> Internal server error
@example <code> <expression>
Provide example responses:
/// @response 200 Json<User> User information
/// @example 200 User::default()
Or with custom values:
/// @example 200 User { id: 1, name: "Alice".into(), email: "alice@example.com".into() }
@tag <tag_name>
Group operations by tags (can be used multiple times):
/// @tag users
/// @tag authentication
Tags help organize your API in Swagger UI by grouping related endpoints together.
@security <scheme_name>
Specify security requirements (can be used multiple times):
/// @security bearer_auth
/// @security api_key
Note: You need to define security schemes in your OpenAPI spec separately.
@id <operation_id>
Set a custom operation ID (defaults to function name):
/// @id getUserById
@hidden
Hide an operation from the documentation:
/// @hidden
#[deprecated]
Use Rust's built-in deprecation attribute to mark endpoints as deprecated:
/// Old endpoint, use /v2/users instead
async
@rovo-ignore
Stop processing doc comment annotations after this point:
/// Get user information.
///
/// Returns the current user's profile information.
///
/// @tag users
/// @response 200 Json<User> User found successfully
/// @rovo-ignore
/// Everything after this line is treated as regular documentation
/// and won't be processed for OpenAPI annotations.
/// You can write @anything here and it won't cause errors.
async
This is useful when you want to include additional developer documentation that shouldn't be part of the API specification.
Router API
Creating a Router
use Router;
let app = new
.route
.with_state;
Method Chaining
Rovo supports the same method chaining as axum:
use ;
new
.route
.route
Nesting Routes
new
.nest
Adding Documentation UI
Swagger UI
new
.route
.with_swagger // Swagger UI at /docs
.with_api_json
.with_state
.finish_api_with_extension
Redoc UI
new
.route
.with_redoc // Redoc UI at /docs
.with_api_json
.with_state
.finish_api_with_extension
Scalar UI
new
.route
.with_scalar // Scalar UI at /docs
.with_api_json
.with_state
.finish_api_with_extension
Multiple UIs
You can serve multiple UIs at different paths:
new
.route
.with_swagger // Swagger UI at /swagger
.with_redoc // Redoc UI at /redoc
.with_scalar // Scalar UI at /scalar
.with_api_json
.with_state
.finish_api_with_extension
Complete Example
See examples/todo_api.rs for a full CRUD API with:
- Create, Read, Update, Delete operations
- Swagger UI integration
- Proper error handling
- Request/response validation
- Nested routing
Run it with:
# Visit http://127.0.0.1:3000 for Swagger UI
Migration Guide
From Axum 0.8+
Migrating an existing axum project to rovo is straightforward:
Step 1: Update Dependencies
[]
# Add these
= "0.1"
= { = "0.15", = ["axum"] }
= "0.8"
# Keep your existing axum
= "0.8"
Step 2: Replace Router Import
// Before
use Router;
// After
use Router;
Step 3: Update Handler Return Types
// Before
use IntoResponse;
async
// After
use IntoApiResponse;
async
Step 4: Add the #[rovo] Macro and Docs
// Before
async
// After
/// Get user by ID
///
/// @tag users
/// @response 200 Json<User> User found
/// @response 404 () User not found
async
Step 5: Update Routing Imports
// Before
use ;
// After
use ;
Step 6: Add OpenAPI Setup
use OpenApi;
use Extension;
async
async
Migration Checklist
- Add
rovoandaidedependencies - Change
axum::Routertorovo::Router - Change
IntoResponsetoIntoApiResponse - Add
#[rovo]macro to handlers - Add doc comments with
@responseannotations - Change
axum::routing::*torovo::routing::* - Add OpenAPI configuration
- Add Swagger UI setup
- Test all endpoints
Incremental Migration
You can migrate gradually by mixing rovo and aide routing:
use get as rovo_get;
use get as aide_get;
new
.route // Migrated with #[rovo]
.route // Not yet migrated
However, we recommend fully migrating to #[rovo] for all endpoints to maintain consistency.
Comparison with aide
| Feature | aide | rovo |
|---|---|---|
| Documentation location | Separate _docs function |
With handler (doc comments) |
| Routing API | aide's api_route() |
Drop-in axum replacement |
| Method chaining | Custom implementation | Native axum syntax |
| Setup complexity | Manual | Helper methods |
| Lines of code per endpoint | ~15-20 | ~5-10 |
Tips and Best Practices
Path Parameters
Use structs with JsonSchema for proper documentation:
async
Complex Response Types
For handlers that return multiple types, use impl IntoApiResponse:
async
Tags for Organization
Use consistent tags to organize your API:
/// @tag users
/// @tag admin
Security Documentation
Define security schemes in your OpenAPI object:
use ;
let mut api = default;
api.components.get_or_insert_default
.security_schemes
.insert;
Then reference it in handlers:
/// @security bearer_auth
async
Troubleshooting
Handler doesn't implement required traits
Error: "doesn't implement IntoApiMethodRouter"
Solution: Make sure you added the #[rovo] macro to your handler:
// Don't forget this!
async
Type mismatch errors with .with_state()
Error: Type mismatch when calling .with_state()
Solution: Add explicit type annotation:
let router: = new
.route
.with_state;
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
GPL-3.0