oxidite-openapi

Crates.iooxidite-openapi
lib.rsoxidite-openapi
version2.0.1
created_at2025-12-07 14:48:42.007641+00
updated_at2026-01-25 01:47:40.259484+00
descriptionOpenAPI/Swagger documentation generation for Oxidite
homepage
repositoryhttps://github.com/meshackbahati/rust-oxidite
max_upload_size
id1971717
size20,782
Meshack Bahati Ouma (meshackbahati)

documentation

README

oxidite-openapi

OpenAPI/Swagger documentation generation for the Oxidite web framework.

Crates.io Docs.rs License

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();
    
    // Add your routes
    router.get("/users", get_users);
    router.post("/users", create_user);
    router.get("/users/:id", get_user);
    
    // Build OpenAPI specification
    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();
    
    // Add route to serve OpenAPI spec
    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};

// Document a GET endpoint
#[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))
}

// Document a POST endpoint
#[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> {
    // Validate payload
    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 {
    /// Unique identifier for the user
    pub id: i64,
    
    /// User's full name
    pub name: String,
    
    /// User's email address
    pub email: String,
    
    /// Timestamp when the user was created
    pub created_at: chrono::DateTime<chrono::Utc>,
    
    /// Timestamp when the user was last updated
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Serialize, Deserialize, Schema)]
pub struct CreateUserRequest {
    /// User's full name (required)
    #[schema(min_length = 1, max_length = 100)]
    pub name: String,
    
    /// User's email address (required)
    #[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")
    // Add API key security scheme
    .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) {
    // First, generate your OpenAPI spec
    let spec = generate_openapi_spec();
    
    // Add the spec endpoint
    router.get("/openapi.json", move |_| async move {
        Ok(response::json(spec.clone()))
    });
    
    // Add Swagger UI
    let swagger_ui = SwaggerUi::new("/swagger-ui/")
        .spec_url("/openapi.json")
        .title("My API - Swagger UI");
    
    // Register Swagger UI routes
    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();
    
    // Validate the specification
    let validator = OpenApiValidator::new();
    let result = validator.validate(&spec);
    
    assert!(result.is_valid(), "OpenAPI spec should be valid");
    
    // Check for specific issues
    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();
    
    // Add your API routes
    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);
    
    // Generate OpenAPI documentation
    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();
    
    // Add documentation endpoints
    router.get("/api/openapi.json", move |_| async move {
        Ok(response::json(spec.clone()))
    });
    
    // Add a catch-all for API docs
    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

Commit count: 42

cargo fmt