Skip to main content

tako_rs_core/
openapi.rs

1//! `OpenAPI` documentation generation integrations.
2//!
3//! Tako ships two integration backends; pick exactly one per project:
4//!
5//! - **`utoipa` — primary, recommended**. Compile-time `OpenAPI` generation via
6//!   derive macros, mature ecosystem, broad community use. Enable with the
7//!   `utoipa` cargo feature.
8//! - **`vespera` — legacy / advanced**. Hand-rolled `OpenAPI` 3.1 builder plus
9//!   route discovery. Kept opt-in for users who need the runtime spec model
10//!   that `utoipa` does not provide. Enable with the `vespera` feature.
11//!
12//! Both backends share the same [`RouteOpenApi`](crate::openapi::RouteOpenApi) metadata attached on the
13//! `Router::route(...)` builder via `summary` / `description` / `tag` /
14//! `response`. The `OpenAPI` documents themselves are produced by whichever
15//! backend the application enables; do not enable both unless you are
16//! intentionally cross-validating the output.
17//!
18//! # Route-Level Integration
19//!
20//! Both integrations support route-level `OpenAPI` metadata:
21//!
22//! ```rust,ignore
23//! use tako::{router::Router, Method};
24//!
25//! let mut router = Router::new();
26//! router.route(Method::GET, "/users/{id}", get_user)
27//!     .summary("Get user by ID")
28//!     .description("Retrieves a user by their unique identifier")
29//!     .tag("users")
30//!     .response(200, "Successful response")
31//!     .response(404, "User not found");
32//! ```
33//!
34//! # Examples
35//!
36//! ## Using utoipa
37//!
38//! ```rust,ignore
39//! use tako::openapi::utoipa::{OpenApi, OpenApiJson, ToSchema};
40//!
41//! #[derive(ToSchema)]
42//! struct User {
43//!     id: u64,
44//!     name: String,
45//! }
46//!
47//! #[derive(OpenApi)]
48//! #[openapi(components(schemas(User)))]
49//! struct ApiDoc;
50//!
51//! async fn openapi(_req: tako::types::Request) -> OpenApiJson {
52//!     OpenApiJson(ApiDoc::openapi())
53//! }
54//! ```
55//!
56//! ## Using vespera
57//!
58//! ```rust,ignore
59//! use tako::openapi::vespera::{OpenApi, Info, VesperaOpenApiJson};
60//!
61//! async fn openapi(_req: tako::types::Request) -> VesperaOpenApiJson {
62//!     let spec = OpenApi {
63//!         info: Info {
64//!             title: "My API".to_string(),
65//!             version: "1.0.0".to_string(),
66//!             ..Default::default()
67//!         },
68//!         ..Default::default()
69//!     };
70//!     VesperaOpenApiJson(spec)
71//! }
72//! ```
73
74use std::collections::BTreeMap;
75
76/// `OpenAPI` metadata that can be attached to a route.
77///
78/// This struct stores operation-level `OpenAPI` information that can be
79/// used to generate `OpenAPI` specifications from Tako routes.
80#[derive(Clone, Debug, Default)]
81pub struct RouteOpenApi {
82  /// Unique identifier for the operation.
83  pub operation_id: Option<String>,
84  /// Short summary of the operation.
85  pub summary: Option<String>,
86  /// Detailed description of the operation.
87  pub description: Option<String>,
88  /// Tags for grouping operations.
89  pub tags: Vec<String>,
90  /// Whether the operation is deprecated.
91  pub deprecated: bool,
92  /// Response descriptions keyed by status code.
93  pub responses: BTreeMap<u16, String>,
94  /// Parameter descriptions.
95  pub parameters: Vec<OpenApiParameter>,
96  /// Request body description.
97  pub request_body: Option<OpenApiRequestBody>,
98  /// Security requirements.
99  pub security: Vec<String>,
100}
101
102/// `OpenAPI` parameter definition.
103#[derive(Clone, Debug, Default)]
104pub struct OpenApiParameter {
105  /// Parameter name.
106  pub name: String,
107  /// Parameter location (query, header, path, cookie).
108  pub location: ParameterLocation,
109  /// Parameter description.
110  pub description: Option<String>,
111  /// Whether the parameter is required.
112  pub required: bool,
113}
114
115/// Location of an `OpenAPI` parameter.
116#[derive(Clone, Debug, Default)]
117pub enum ParameterLocation {
118  #[default]
119  Query,
120  Header,
121  Path,
122  Cookie,
123}
124
125/// `OpenAPI` request body definition.
126#[derive(Clone, Debug, Default)]
127pub struct OpenApiRequestBody {
128  /// Description of the request body.
129  pub description: Option<String>,
130  /// Whether the request body is required.
131  pub required: bool,
132  /// Content type (e.g., "application/json").
133  pub content_type: String,
134  /// Schema properties for the request body (name, type, description).
135  pub schema_properties: Vec<RequestBodyProperty>,
136}
137
138/// A property definition for request body schema.
139#[derive(Clone, Debug, Default)]
140pub struct RequestBodyProperty {
141  /// Property name.
142  pub name: String,
143  /// Property type (e.g., "string", "integer", "boolean").
144  pub property_type: String,
145  /// Property description.
146  pub description: Option<String>,
147}
148
149#[cfg(feature = "utoipa")]
150#[cfg_attr(docsrs, doc(cfg(feature = "utoipa")))]
151pub mod utoipa;
152
153#[cfg(feature = "vespera")]
154#[cfg_attr(docsrs, doc(cfg(feature = "vespera")))]
155pub mod vespera;
156
157/// `OpenAPI` UI helpers (Swagger UI, Scalar, `RapiDoc`, `Redoc`).
158pub mod ui;