11 releases
| 0.2.0 | Mar 23, 2026 |
|---|---|
| 0.1.9 | Mar 4, 2026 |
#218 in Visualization
78KB
971 lines
openapi-ui
A Rust library for generating custom UI for OpenAPI/Swagger documentation.
Table of Contents
- Features
- Installation
- Quick Start
- Web Framework Integration
- Theming
- API Reference
- OpenAPI Structures
- Error Handling
- Complete Example
- License
Features
- ✅ OpenAPI 3.0.x and 3.1.x support
- ✅ Light and dark themes with toggle
- ✅ Responsive sidebar navigation
- ✅ Endpoint search/filter
- ✅ Syntax highlighting (Highlight.js)
- ✅ Code copy buttons
- ✅ Method color coding
- ✅ Parameter tables
- ✅ Request/response examples
- ✅ Security scheme display
- ✅ Tag-based grouping
Installation
Add this to your Cargo.toml:
[dependencies]
openapi-ui = "0.1.9"
Quick Start
Generate from OpenAPI JSON
use openapi_ui::{generate_docs, ThemeMode};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let openapi_json = r#"{
"openapi": "3.0.0",
"info": {
"title": "My API",
"version": "1.0.0",
"description": "API documentation"
},
"paths": {
"/users": {
"get": {
"summary": "Get all users",
"responses": {
"200": { "description": "Success" }
}
}
}
}
}"#;
// With system theme (default - allows user to toggle light/dark)
let html = generate_docs(openapi_json, ThemeMode::System, None, None)?;
std::fs::write("docs.html", html)?;
Ok(())
}
Theme Modes
use openapi_ui::{generate_docs, ThemeMode};
// System mode - both themes with user toggle (default)
let html = generate_docs(json, ThemeMode::System, None, None)?;
// Light mode only - no dark theme
let html = generate_docs(json, ThemeMode::Light, None, None)?;
// Dark mode only - no light theme
let html = generate_docs(json, ThemeMode::Dark, None, None)?;
Using the Builder
use openapi_ui::{UIBuilder, OpenAPISpec};
let spec: OpenAPISpec = serde_json::from_str(openapi_json)?;
let html = UIBuilder::new(spec)
.theme("system") // "light", "dark", or "system"
.build();
std::fs::write("docs.html", html)?;
Web Framework Integration
openapi-ui is framework-agnostic and returns a simple String of HTML. This makes it easy to integrate with any Rust web framework.
Check the examples/ directory for complete implementations:
Basic Axum Integration
use axum::{response::Html, routing::get, Router};
use openapi_ui::{generate_docs, ThemeMode};
async fn show_docs() -> Html<String> {
let openapi_json = "..."; // Your OpenAPI JSON
let html = generate_docs(openapi_json, ThemeMode::System, None, None).unwrap();
Html(html)
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/docs", get(show_docs));
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Using with utoipa
The OpenAPI JSON string can be generated at compile time using utoipa. Annotate your routes and models, then pass the generated JSON to openapi-ui:
use utoipa::OpenApi;
use openapi_ui::{generate_docs, ThemeMode};
#[derive(OpenApi)]
#[openapi(
paths(get_users, create_user),
components(schemas(User))
)]
struct ApiDoc;
// Generate the OpenAPI JSON from utoipa
let openapi_json = ApiDoc::openapi().to_pretty_json().unwrap();
// Pass it to openapi-ui
let html = generate_docs(&openapi_json, ThemeMode::System, None, None).unwrap();
std::fs::write("docs.html", html).unwrap();
All framework examples in the examples/ directory include comments showing how to integrate with utoipa.
Theming
Includes built-in light and dark themes with a theme toggle.
Default Theme Variables
Light Theme
| Variable | Value | Description |
|---|---|---|
--bg |
#faf9f5 |
Main background |
--bg-card |
#ffffff |
Card backgrounds |
--t1 |
#1f1e1d |
Primary text |
--accent |
#c96442 |
Accent color (terracotta) |
--green |
#2d8a4e |
GET method, 2xx status |
--blue |
#1c6bbb |
POST method |
--orange |
#b56613 |
PUT method, 4xx status |
--red |
#c0392b |
DELETE method, 5xx status |
Dark Theme
| Variable | Value | Description |
|---|---|---|
--bg |
#1e1c19 |
Main background |
--bg-card |
#2d2b27 |
Card backgrounds |
--t1 |
#ede8df |
Primary text |
--accent |
#d4714f |
Accent color (terracotta) |
--green |
#4caf72 |
GET method, 2xx status |
--blue |
#5a9fe0 |
POST method |
--orange |
#d4943a |
PUT method, 4xx status |
--red |
#e05c4b |
DELETE method, 5xx status |
Customizing Themes
Use the custom_css parameter of generate_docs to inject custom CSS that overrides theme variables:
use openapi_ui::{generate_docs, ThemeMode};
let custom_css = r#"
:root {
--accent: #3b82f6; /* Custom blue accent */
--accent-h: #2563eb; /* Hover state */
--accent-bg: #eff6ff; /* Accent background tint */
}
[data-theme="dark"] {
--accent: #60a5fa; /* Lighter blue for dark mode */
--accent-h: #93c5fd;
--accent-bg: #1e3a5f;
}
"#;
let html = generate_docs(openapi_json, ThemeMode::System, Some(custom_css), None)?;
std::fs::write("docs.html", html)?;
Example: Brand Colors
let brand_css = r#"
:root {
/* Brand: Forest Green */
--accent: #2d5a3d;
--accent-h: #3d7a52;
--accent-bg: #e8f5e9;
/* Override method colors if needed */
--green: #2d5a3d; /* GET */
--blue: #1b5e7a; /* POST */
--purple: #5a3d7a; /* PATCH */
}
[data-theme="dark"] {
--accent: #4caf72;
--accent-h: #66bb8a;
--accent-bg: #1b3a25;
}
"#;
Using Theme CSS Directly
You can also access the built-in theme CSS for reference or extension:
use openapi_ui::{Theme, get_theme_css, get_complete_theme_css};
// Get light theme CSS
let light_css = Theme::Light.as_css();
// Get dark theme CSS
let dark_css = Theme::Dark.as_css();
// Get both themes (for system theme switching)
let all_css = get_complete_theme_css();
// Get specific theme by name
let css = get_theme_css("dark");
API Reference
Core Functions
generate_docs(json: &str, mode: ThemeMode, custom_css: Option<&str>) -> Result<String>
Generate HTML documentation from an OpenAPI JSON string with theme mode and optional custom CSS.
use openapi_ui::{generate_docs, ThemeMode};
// System mode (default) - both themes with user toggle
let html = generate_docs(&openapi_json, ThemeMode::System, None, None)?;
// Light mode only
let html = generate_docs(&openapi_json, ThemeMode::Light, None, None)?;
// Dark mode only
let html = generate_docs(&openapi_json, ThemeMode::Dark, None, None)?;
// With custom CSS
let custom_css = ":root { --accent: #3b82f6; }";
let html = generate_docs(&openapi_json, ThemeMode::System, Some(custom_css), None)?;
generate_ui(spec: &OpenAPISpec) -> String
Generate HTML from a parsed OpenAPISpec struct.
let spec: OpenAPISpec = serde_json::from_str(&openapi_json)?;
let html = openapi_ui::generate_ui(&spec);
generate_base_ui() -> String
Generate a template with sample Petstore data (useful for demos).
let html = openapi_ui::generate_base_ui();
ThemeMode Enum
use openapi_ui::ThemeMode;
// Theme variants
ThemeMode::Light // Light theme only
ThemeMode::Dark // Dark theme only
ThemeMode::System // Both themes with toggle (default)
// Convert from string
let mode = ThemeMode::from_str("light");
// Convert to string
let mode_str = ThemeMode::System.as_str(); // "system"
UIBuilder
Fluent builder for customizing output:
use openapi_ui::UIBuilder;
let html = UIBuilder::new(spec)
.theme("light") // Default: "system"
.base_url("https://api.example.com")
.build();
Theme Functions
use openapi_ui::{Theme, get_theme_css, get_complete_theme_css};
// Enum variants
Theme::Light
Theme::Dark
// Convert string to Theme
let theme = Theme::from_str("dark");
// Get CSS for a theme
let css = Theme::Light.as_css();
// Get all theme CSS
let css = get_complete_theme_css();
OpenAPI Structures
The openapi module provides types matching the OpenAPI 3.x specification:
use openapi_ui::{
OpenAPISpec, Info, Server, PathItem, Operation,
Parameter, ParameterLocation, Response, Schema,
SecurityScheme, Tag,
};
Building a Spec Programmatically
use openapi_ui::{OpenAPISpec, Info, Server, PathItem, Operation, Response, Schema, SchemaType};
use std::collections::HashMap;
let mut paths = HashMap::new();
// Add a GET /users endpoint
paths.insert("/users".to_string(), PathItem {
get: Some(Operation {
summary: Some("List all users".to_string()),
description: Some("Returns a list of users".to_string()),
tags: Some(vec!["users".to_string()]),
operation_id: Some("getUsers".to_string()),
parameters: None,
request_body: None,
responses: {
let mut responses = HashMap::new();
responses.insert("200".to_string(), Response {
description: "Successful response".to_string(),
content: None,
headers: None,
links: None,
});
responses
},
deprecated: None,
security: None,
servers: None,
external_docs: None,
}),
put: None,
post: None,
delete: None,
options: None,
head: None,
patch: None,
trace: None,
servers: None,
parameters: None,
summary: None,
description: None,
});
let spec = OpenAPISpec {
openapi: "3.0.0".to_string(),
info: Info {
title: "My API".to_string(),
version: "1.0.0".to_string(),
description: Some("API documentation".to_string()),
terms_of_service: None,
contact: None,
license: None,
x_logo: None,
},
servers: vec![
Server {
url: "https://api.example.com/v1".to_string(),
description: Some("Production".to_string()),
},
],
paths,
components: None,
security: None,
tags: Some(vec![
Tag {
name: "users".to_string(),
description: Some("User management endpoints".to_string()),
external_docs: None,
},
]),
external_docs: None,
};
let html = openapi_ui::generate_ui(&spec);
Error Handling
use openapi_ui::{generate_docs, UIError};
match generate_docs(invalid_json, ThemeMode::System, None, None) {
Ok(html) => println!("Generated {} bytes", html.len()),
Err(UIError::JsonError(e)) => eprintln!("Invalid JSON: {}", e),
Err(UIError::ParseError(e)) => eprintln!("Parse error: {}", e),
Err(UIError::IoError(e)) => eprintln!("IO error: {}", e),
Err(UIError::ConfigError(e)) => eprintln!("Config error: {}", e),
}
Or with ?:
fn generate() -> Result<(), openapi_ui::UIError> {
let html = generate_docs(json, ThemeMode::System, None, None)?;
std::fs::write("docs.html", html)?;
Ok(())
}
Complete Example
use openapi_ui::{generate_docs, ThemeMode};
use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Read OpenAPI spec from file
let json = fs::read_to_string("openapi.json")?;
// Define custom branding
let custom_css = r#"
:root {
--accent: #7c3aed;
--accent-h: #6d28d9;
--accent-bg: #f5f3ff;
}
[data-theme="dark"] {
--accent: #a78bfa;
--accent-h: #c4b5fd;
--accent-bg: #2e1065;
}
"#;
// Generate with system theme (allows user toggle) and custom branding
let html = generate_docs(&json, ThemeMode::System, Some(custom_css), None)?;
// Write output
fs::write("api-docs.html", html)?;
println!("Generated api-docs.html");
Ok(())
}
License
MIT
Dependencies
~0.4–1.3MB
~28K SLoC