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