Skip to main content

rustapi_openapi/
lib.rs

1//! OpenAPI documentation for RustAPI
2//!
3//! This crate provides OpenAPI specification generation and Swagger UI serving
4//! for RustAPI applications with a native OpenAPI model and schema engine.
5//!
6//! # Features
7//!
8//! - **OpenAPI 3.0.3** and **OpenAPI 3.1.0** specification support
9//! - Swagger UI serving at `/docs`
10//! - JSON spec at `/openapi.json`
11//! - Schema derivation via `#[derive(Schema)]`
12//! - **API versioning** with multiple strategies (path, header, query, accept)
13//! - **JSON Schema 2020-12** support for OpenAPI 3.1
14//! - **Webhook definitions** support
15//!
16//! # OpenAPI 3.1 Usage
17//!
18//! ```rust,ignore
19//! use rustapi_openapi::v31::{OpenApi31Spec, Webhook, JsonSchema2020};
20//!
21//! let spec = OpenApi31Spec::new("My API", "1.0.0")
22//!     .description("API with OpenAPI 3.1 support")
23//!     .webhook("orderPlaced", Webhook::with_summary("Order notification"))
24//!     .schema("User", JsonSchema2020::object()
25//!         .with_property("id", JsonSchema2020::integer())
26//!         .with_property("name", JsonSchema2020::string())
27//!         .with_required("id"))
28//!     .build();
29//! ```
30//!
31//! # API Versioning Usage
32//!
33//! ```rust,ignore
34//! use rustapi_openapi::versioning::{VersionRouter, ApiVersion, VersionStrategy};
35//!
36//! let router = VersionRouter::new()
37//!     .strategy(VersionStrategy::path())
38//!     .default_version(ApiVersion::v1())
39//!     .version(ApiVersion::v1(), VersionedRouteConfig::version(ApiVersion::v1()))
40//!     .version(ApiVersion::v2(), VersionedRouteConfig::version(ApiVersion::v2()));
41//! ```
42//!
43//! # Legacy Usage (OpenAPI 3.0)
44//!
45//! ```rust,ignore
46//! use rustapi_rs::prelude::*;
47//!
48//! #[derive(Serialize, Schema)]
49//! struct User {
50//!     id: i64,
51//!     name: String,
52//! }
53//!
54//! RustApi::new()
55//!     .route("/users", get(list_users))
56//!     .docs("/docs")
57//!     .run("127.0.0.1:8080")
58//!     .await
59//! ```
60
61// Needed for proc-macro to refer to this crate
62extern crate self as rustapi_openapi;
63
64mod config;
65#[cfg(feature = "redoc")]
66mod redoc;
67pub mod schema;
68mod schemas;
69mod spec;
70#[cfg(feature = "swagger-ui")]
71mod swagger;
72#[cfg(test)]
73mod tests;
74
75// API versioning support
76pub mod versioning;
77
78pub use config::OpenApiConfig;
79pub use schemas::{
80    ErrorBodySchema, ErrorSchema, FieldErrorSchema, ValidationErrorBodySchema,
81    ValidationErrorSchema,
82};
83pub use spec::{
84    ApiInfo, MediaType, OpenApiSpec, Operation, OperationModifier, Parameter, PathItem,
85    RequestBody, ResponseModifier, ResponseSpec, SchemaRef,
86};
87
88// Re-export Schema derive macro
89pub use rustapi_macros::Schema;
90
91use bytes::Bytes;
92use http::{header, Response, StatusCode};
93use http_body_util::Full;
94
95/// Generate OpenAPI JSON response
96pub fn openapi_json(spec: &OpenApiSpec) -> Response<Full<Bytes>> {
97    match serde_json::to_string_pretty(&spec.to_json()) {
98        Ok(json) => Response::builder()
99            .status(StatusCode::OK)
100            .header(header::CONTENT_TYPE, "application/json")
101            .body(Full::new(Bytes::from(json)))
102            .unwrap(),
103        Err(_) => Response::builder()
104            .status(StatusCode::INTERNAL_SERVER_ERROR)
105            .body(Full::new(Bytes::from("Failed to serialize OpenAPI spec")))
106            .unwrap(),
107    }
108}
109
110/// Generate Swagger UI HTML response
111#[cfg(feature = "swagger-ui")]
112pub fn swagger_ui_html(openapi_url: &str) -> Response<Full<Bytes>> {
113    let html = swagger::generate_swagger_html(openapi_url);
114    Response::builder()
115        .status(StatusCode::OK)
116        .header(header::CONTENT_TYPE, "text/html; charset=utf-8")
117        .body(Full::new(Bytes::from(html)))
118        .unwrap()
119}
120
121/// Generate ReDoc HTML response
122///
123/// ReDoc provides a three-panel API documentation interface.
124///
125/// # Example
126/// ```rust,ignore
127/// use rustapi_openapi::redoc_html;
128/// let response = redoc_html("/openapi.json");
129/// ```
130#[cfg(feature = "redoc")]
131pub fn redoc_html(openapi_url: &str) -> Response<Full<Bytes>> {
132    let html = redoc::generate_redoc_html(openapi_url, None);
133    Response::builder()
134        .status(StatusCode::OK)
135        .header(header::CONTENT_TYPE, "text/html; charset=utf-8")
136        .body(Full::new(Bytes::from(html)))
137        .unwrap()
138}
139
140/// Generate ReDoc HTML response with custom configuration
141#[cfg(feature = "redoc")]
142pub fn redoc_html_with_config(
143    openapi_url: &str,
144    title: Option<&str>,
145    config: &redoc::RedocConfig,
146) -> Response<Full<Bytes>> {
147    let html = redoc::generate_redoc_html_with_config(openapi_url, title, config);
148    Response::builder()
149        .status(StatusCode::OK)
150        .header(header::CONTENT_TYPE, "text/html; charset=utf-8")
151        .body(Full::new(Bytes::from(html)))
152        .unwrap()
153}
154
155#[cfg(feature = "redoc")]
156pub use redoc::{RedocConfig, RedocTheme};