oxidite-openapi
OpenAPI/Swagger documentation generation for the Oxidite web framework.

Overview
oxidite-openapi provides automatic OpenAPI/Swagger documentation generation for Oxidite web applications. It allows you to generate comprehensive API documentation that follows the OpenAPI specification, making it easy for developers to understand and consume your APIs.
Installation
Add this to your Cargo.toml:
[dependencies]
oxidite-openapi = "0.2.0"
Features
- Automatic documentation generation - Generate OpenAPI specs from your route definitions
- Swagger UI integration - Built-in Swagger UI for interactive API documentation
- Schema inference - Automatically infer schemas from Rust types
- Parameter documentation - Document query, path, and header parameters
- Response documentation - Describe response bodies and status codes
- Request body documentation - Document request schemas
- Security schemes - Document authentication methods
- Custom annotations - Fine-tune documentation with custom attributes
- Multiple OpenAPI versions - Support for OpenAPI 3.0 and 3.1
Usage
Basic Setup
Add OpenAPI documentation to your Oxidite application:
use oxidite::prelude::*;
use oxidite_openapi::{OpenApiSpec, OpenApiBuilder};
#[tokio::main]
async fn main() -> Result<()> {
let mut router = Router::new();
router.get("/users", get_users);
router.post("/users", create_user);
router.get("/users/:id", get_user);
let spec = OpenApiBuilder::new()
.title("My API")
.version("1.0.0")
.description("My awesome API built with Oxidite")
.contact_name("API Support")
.contact_email("support@example.com")
.license_name("MIT")
.build();
router.get("/openapi.json", move |_| async move {
Ok(response::json(spec.clone()))
});
Server::new(router)
.listen("127.0.0.1:3000".parse().unwrap())
.await
}
Documenting Endpoints
Document your API endpoints with detailed information:
use oxidite::prelude::*;
use oxidite_openapi::{EndpointDoc, Parameter, Response};
#[EndpointDoc(
summary = "Get all users",
description = "Returns a list of all users in the system",
parameters = [
Parameter::query("page", "integer", "Page number", Some("1")),
Parameter::query("limit", "integer", "Items per page", Some("10"))
],
responses = [
Response::ok("List of users", "Vec<User>"),
Response::bad_request("Invalid parameters")
]
)]
async fn get_users(
Query(params): Query<PaginationParams>,
State(db): State<Database>
) -> Result<OxiditeResponse> {
let users = User::all(&db).limit(params.limit).offset((params.page - 1) * params.limit).await?;
Ok(response::json(users))
}
#[EndpointDoc(
summary = "Create a new user",
description = "Creates a new user in the system",
request_body = "CreateUserRequest",
responses = [
Response::created("User created", "User"),
Response::conflict("User already exists"),
Response::unprocessable_entity("Validation error")
]
)]
async fn create_user(
Json(payload): Json<CreateUserRequest>,
State(db): State<Database>
) -> Result<OxiditeResponse> {
if !is_valid_email(&payload.email) {
return Err(OxiditeError::Validation("Invalid email format".to_string()));
}
let user = User {
id: 0,
name: payload.name,
email: payload.email,
created_at: chrono::Utc::now(),
updated_at: chrono::Utc::now(),
};
user.create(&db).await?;
Ok(response::json(user).status(http::StatusCode::CREATED))
}
Schema Definitions
Define schemas for your API models:
use oxidite_openapi::Schema;
#[derive(Serialize, Deserialize, Schema)]
pub struct User {
pub id: i64,
pub name: String,
pub email: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Serialize, Deserialize, Schema)]
pub struct CreateUserRequest {
#[schema(min_length = 1, max_length = 100)]
pub name: String,
#[schema(pattern = r"^[^@]+@[^@]+\.[^@]+$")]
pub email: String,
}
Security Documentation
Document authentication and authorization:
use oxidite_openapi::{SecurityScheme, ApiKeyLocation};
let spec = OpenApiBuilder::new()
.title("My API")
.version("1.0.0")
.security_scheme(
"api_key",
SecurityScheme::ApiKey {
name: "X-API-Key".to_string(),
location: ApiKeyLocation::Header,
description: Some("API key for authentication".to_string()),
}
)
.build();
Serving Swagger UI
Serve the interactive Swagger UI with your documentation:
use oxidite::prelude::*;
use oxidite_openapi::{OpenApiSpec, SwaggerUi};
async fn setup_swagger_ui(router: &mut Router) {
let spec = generate_openapi_spec();
router.get("/openapi.json", move |_| async move {
Ok(response::json(spec.clone()))
});
let swagger_ui = SwaggerUi::new("/swagger-ui/")
.spec_url("/openapi.json")
.title("My API - Swagger UI");
router.get("/swagger-ui/", swagger_ui.handler());
router.get("/swagger-ui/*", swagger_ui.handler());
}
Custom Documentation Attributes
Fine-tune your API documentation:
use oxidite_openapi::{EndpointDoc, Parameter, Response, Schema};
#[EndpointDoc(
operation_id = "get_user_by_id",
summary = "Get user by ID",
description = "Retrieve a specific user by their unique identifier",
tags = ["users"],
parameters = [
Parameter::path("id", "integer", "User ID"),
],
responses = [
Response::ok("User details", "User"),
Response::not_found("User not found"),
],
deprecated = false
)]
async fn get_user(
Path(params): Path<UserId>,
State(db): State<Database>
) -> Result<OxiditeResponse> {
match User::find(&db, params.id).await? {
Some(user) => Ok(response::json(user)),
None => Err(OxiditeError::NotFound("User not found".to_string())),
}
}
Validation and Testing
Validate your OpenAPI specification:
use oxidite_openapi::OpenApiValidator;
#[tokio::test]
async fn test_openapi_spec_validity() {
let spec = generate_openapi_spec();
let validator = OpenApiValidator::new();
let result = validator.validate(&spec);
assert!(result.is_valid(), "OpenAPI spec should be valid");
for warning in result.warnings() {
eprintln!("Warning: {}", warning);
}
}
Integration with Oxidite
The OpenAPI integration works seamlessly with Oxidite's architecture:
use oxidite::prelude::*;
use oxidite_openapi::OpenApiBuilder;
async fn create_documented_app() -> Router {
let mut router = Router::new();
router.get("/api/users", get_users);
router.post("/api/users", create_user);
router.get("/api/users/:id", get_user);
router.put("/api/users/:id", update_user);
router.delete("/api/users/:id", delete_user);
let spec = OpenApiBuilder::new()
.title("User Management API")
.version("1.0.0")
.description("API for managing users")
.server("https://api.example.com", "Production server")
.server("https://staging-api.example.com", "Staging server")
.build();
router.get("/api/openapi.json", move |_| async move {
Ok(response::json(spec.clone()))
});
router.get("/api/docs", |_req| async move {
Ok(response::html(include_str!("../docs/swagger.html")))
});
router
}
Best Practices
- Document all public endpoints - Every public API endpoint should have documentation
- Use meaningful descriptions - Provide clear, concise descriptions for all endpoints and parameters
- Include examples - Add request/response examples where helpful
- Keep documentation up-to-date - Update docs when changing API behavior
- Validate your specs - Regularly validate your OpenAPI specifications
- Use appropriate HTTP status codes - Document all possible response codes
License
MIT