product_os_openapi/lib.rs
1//! # Product OS OpenAPI
2//!
3//! A `no_std` compatible library for working with OpenAPI/Swagger specifications.
4//!
5//! This crate provides strongly-typed data structures for both OpenAPI v2 (Swagger) and
6//! OpenAPI v3.x specifications, with full serialization and deserialization support via `serde`.
7//!
8//! ## Features
9//!
10//! - **Dual Version Support**: Works with both Swagger 2.0 and OpenAPI 3.x specifications
11//! - **no_std Compatible**: Can be used in embedded and constrained environments
12//! - **Type Safety**: Strongly typed structs with proper validation through the type system
13//! - **Serde Integration**: Full JSON serialization/deserialization support
14//!
15//! ## Cargo Features
16//!
17//! | Feature | Default | Description |
18//! |---------|---------|-------------|
19//! | `std` | Yes | Standard library support via `no-std-compat/std` |
20//! | `openapi` | Yes | Serde serialization/deserialization for OpenAPI structs |
21//!
22//! ## Usage Examples
23//!
24//! ### Parsing OpenAPI v3 Specification
25//!
26//! ```rust
27//! use product_os_openapi::{ProductOSOpenAPI, Info};
28//! use serde_json;
29//!
30//! let json = r#"{
31//! "openapi": "3.0.0",
32//! "info": {
33//! "title": "My API",
34//! "version": "1.0.0"
35//! }
36//! }"#;
37//!
38//! let spec: ProductOSOpenAPI = serde_json::from_str(json)
39//! .expect("Failed to parse OpenAPI spec");
40//!
41//! assert_eq!(spec.info.title, "My API");
42//! ```
43//!
44//! ### Parsing Swagger v2 Specification
45//!
46//! ```rust
47//! use product_os_openapi::ProductOSOpenAPI;
48//! use serde_json;
49//!
50//! let json = r#"{
51//! "swagger": "2.0",
52//! "info": {
53//! "title": "My API",
54//! "version": "1.0.0"
55//! },
56//! "host": "api.example.com",
57//! "basePath": "/v1"
58//! }"#;
59//!
60//! let spec: ProductOSOpenAPI = serde_json::from_str(json)
61//! .expect("Failed to parse Swagger spec");
62//!
63//! assert_eq!(spec.swagger, Some("2.0".to_owned()));
64//! ```
65//!
66//! ### Creating Specifications Programmatically
67//!
68//! ```rust
69//! use product_os_openapi::{ProductOSOpenAPI, Info};
70//! use serde_json;
71//!
72//! let spec = ProductOSOpenAPI {
73//! openapi: Some("3.0.0".to_owned()),
74//! info: Info {
75//! title: "My API".to_owned(),
76//! version: "1.0.0".to_owned(),
77//! description: Some("A test API".to_owned()),
78//! summary: None,
79//! terms_of_service: None,
80//! contact: None,
81//! license: None,
82//! },
83//! json_schema_dialect: None,
84//! servers: None,
85//! paths: None,
86//! webhooks: None,
87//! components: None,
88//! definitions: None,
89//! security: None,
90//! tags: None,
91//! external_docs: None,
92//! swagger: None,
93//! host: None,
94//! base_path: None,
95//! schemes: None,
96//! consumes: None,
97//! produces: None,
98//! };
99//!
100//! let json = serde_json::to_string_pretty(&spec).unwrap();
101//! ```
102//!
103//! ## OpenAPI v2 vs v3
104//!
105//! This crate supports both versions by including fields from both specifications in the
106//! main [`ProductOSOpenAPI`] struct:
107//!
108//! - **OpenAPI v3** uses: `openapi`, `servers`, `components`, `webhooks`, `json_schema_dialect`
109//! - **Swagger v2** uses: `swagger`, `host`, `base_path`, `schemes`, `consumes`, `produces`, `definitions`
110//! - **Both versions** share: `info`, `paths`, `security`, `tags`, `external_docs`
111//!
112//! When deserializing, the appropriate fields will be populated based on the specification version.
113
114#![no_std]
115extern crate no_std_compat as std;
116extern crate alloc;
117
118use std::prelude::v1::*;
119
120use std::collections::BTreeMap;
121use std::fmt;
122use serde::{Deserialize, Serialize};
123
124/// Type alias for callback definitions.
125///
126/// Callbacks are complex nested structures mapping callback names to expressions
127/// to runtime expressions to Path Items.
128pub type Callbacks = BTreeMap<String, BTreeMap<String, BTreeMap<String, PathItem>>>;
129
130
131/// Root structure for OpenAPI/Swagger specifications.
132///
133/// This struct supports both OpenAPI v3.x and Swagger v2.0 specifications by including
134/// fields from both versions. When parsing a specification, the appropriate fields will
135/// be populated based on the version.
136///
137/// # OpenAPI v3.x Fields
138///
139/// - `openapi` - Version string (required for v3)
140/// - `servers` - Server connectivity information
141/// - `components` - Reusable components
142/// - `webhooks` - Incoming webhook definitions
143/// - `json_schema_dialect` - JSON Schema dialect URI
144///
145/// # Swagger v2.0 Fields
146///
147/// - `swagger` - Version string (required for v2, must be "2.0")
148/// - `host` - Host serving the API
149/// - `base_path` - Base path for all API paths
150/// - `schemes` - Transfer protocols (http, https, ws, wss)
151/// - `consumes` - MIME types the API can consume
152/// - `produces` - MIME types the API can produce
153/// - `definitions` - Data type definitions (v2 equivalent of components.schemas)
154///
155/// # Shared Fields (Both Versions)
156///
157/// - `info` - API metadata (required)
158/// - `paths` - Available API paths and operations
159/// - `security` - Security requirements
160/// - `tags` - Tag definitions for grouping operations
161/// - `external_docs` - External documentation
162///
163/// # Examples
164///
165/// ```rust
166/// use product_os_openapi::{ProductOSOpenAPI, Info};
167/// use serde_json;
168///
169/// // OpenAPI v3 example
170/// let v3_json = r#"{
171/// "openapi": "3.0.0",
172/// "info": {
173/// "title": "My API",
174/// "version": "1.0.0"
175/// }
176/// }"#;
177///
178/// let v3_spec: ProductOSOpenAPI = serde_json::from_str(v3_json).unwrap();
179/// assert_eq!(v3_spec.openapi, Some("3.0.0".to_owned()));
180///
181/// // Swagger v2 example
182/// let v2_json = r#"{
183/// "swagger": "2.0",
184/// "info": {
185/// "title": "My API",
186/// "version": "1.0.0"
187/// }
188/// }"#;
189///
190/// let v2_spec: ProductOSOpenAPI = serde_json::from_str(v2_json).unwrap();
191/// assert_eq!(v2_spec.swagger, Some("2.0".to_owned()));
192/// ```
193#[derive(Clone, Debug, Deserialize, Serialize)]
194#[serde(rename_all = "camelCase")]
195pub struct ProductOSOpenAPI {
196 /// The OpenAPI Specification version (e.g., "3.0.0", "3.1.0"). Required for OpenAPI v3.
197 pub openapi: Option<String>,
198
199 /// Metadata about the API. This field is required in both OpenAPI v3 and Swagger v2.
200 pub info: Info,
201
202 /// The default JSON Schema dialect for Schema Objects. Must be a URI.
203 /// Only applicable to OpenAPI v3.1+.
204 pub json_schema_dialect: Option<String>,
205
206 /// An array of Server objects providing connectivity information.
207 /// If not provided or empty, the default is a server with url "/".
208 /// Only applicable to OpenAPI v3.
209 pub servers: Option<Vec<Server>>,
210
211 /// The available paths and operations for the API.
212 /// Maps path strings (e.g., "/users/{id}") to PathItem objects.
213 pub paths: Option<BTreeMap<String, PathItem>>,
214
215 /// Incoming webhooks that may be received as part of this API.
216 /// Only applicable to OpenAPI v3.1+.
217 pub webhooks: Option<BTreeMap<String, PathItem>>,
218
219 /// Reusable components including schemas, responses, parameters, etc.
220 /// Only applicable to OpenAPI v3.
221 pub components: Option<Components>,
222
223 /// Data type definitions. This is the Swagger v2 equivalent of `components.schemas`.
224 /// Only applicable to Swagger v2.
225 pub definitions: Option<BTreeMap<String, Schema>>,
226
227 /// Global security requirements. Individual operations can override this.
228 /// Each entry represents alternative security requirements (logical OR).
229 pub security: Option<Vec<BTreeMap<String, Vec<String>>>>,
230
231 /// A list of tags for grouping operations with additional metadata.
232 pub tags: Option<Vec<Tag>>,
233
234 /// Additional external documentation for the API.
235 pub external_docs: Option<ExternalDocs>,
236
237 /// The Swagger Specification version. Must be "2.0" for Swagger v2.
238 /// Only applicable to Swagger v2.
239 pub swagger: Option<String>,
240
241 /// The host (name or IP) serving the API. May include a port.
242 /// Only applicable to Swagger v2.
243 pub host: Option<String>,
244
245 /// The base path on which the API is served, relative to the host.
246 /// Must start with a leading slash "/".
247 /// Only applicable to Swagger v2.
248 pub base_path: Option<String>,
249
250 /// Transfer protocols supported by the API (e.g., "http", "https", "ws", "wss").
251 /// Only applicable to Swagger v2.
252 pub schemes: Option<Vec<String>>,
253
254 /// MIME types the API can consume globally.
255 /// Can be overridden on specific operations.
256 /// Only applicable to Swagger v2.
257 pub consumes: Option<Vec<String>>,
258
259 /// MIME types the API can produce globally.
260 /// Can be overridden on specific operations.
261 /// Only applicable to Swagger v2.
262 pub produces: Option<Vec<String>>,
263}
264
265/// Metadata about the API.
266///
267/// The Info object provides essential information about the API including its title,
268/// version, description, and contact/license information.
269///
270/// # Required Fields
271///
272/// - `title` - The title of the API
273/// - `version` - The version of the API (distinct from the OpenAPI version)
274///
275/// # Example
276///
277/// ```rust
278/// use product_os_openapi::{Info, Contact, License};
279///
280/// let info = Info {
281/// title: "My API".to_owned(),
282/// version: "1.0.0".to_owned(),
283/// summary: Some("A brief summary".to_owned()),
284/// description: Some("A detailed description".to_owned()),
285/// terms_of_service: Some("https://example.com/terms".to_owned()),
286/// contact: Some(Contact {
287/// name: Some("API Support".to_owned()),
288/// url: Some("https://example.com".to_owned()),
289/// email: "support@example.com".to_owned(),
290/// }),
291/// license: Some(License {
292/// name: "Apache 2.0".to_owned(),
293/// identifier: Some("Apache-2.0".to_owned()),
294/// url: Some("https://www.apache.org/licenses/LICENSE-2.0".to_owned()),
295/// }),
296/// };
297/// ```
298#[derive(Clone, Debug, Deserialize, Serialize)]
299#[serde(rename_all = "camelCase")]
300pub struct Info {
301 /// The title of the API. This field is required.
302 pub title: String,
303
304 /// A short summary of the API. (OpenAPI v3.1+)
305 pub summary: Option<String>,
306
307 /// A description of the API. CommonMark syntax may be used for rich text.
308 pub description: Option<String>,
309
310 /// A URL to the Terms of Service for the API. Must be a valid URL.
311 pub terms_of_service: Option<String>,
312
313 /// Contact information for the exposed API.
314 pub contact: Option<Contact>,
315
316 /// License information for the exposed API.
317 pub license: Option<License>,
318
319 /// The version of the API. This field is required.
320 /// Note: This is distinct from the OpenAPI Specification version.
321 pub version: String,
322}
323
324/// Contact information for the API.
325///
326/// Provides contact details for the API maintainers or support team.
327#[derive(Clone, Debug, Deserialize, Serialize)]
328#[serde(rename_all = "camelCase")]
329pub struct Contact {
330 /// The identifying name of the contact person/organization.
331 pub name: Option<String>,
332
333 /// The URL pointing to the contact information. Must be a valid URL.
334 pub url: Option<String>,
335
336 /// The email address of the contact person/organization.
337 pub email: String
338}
339
340/// License information for the API.
341///
342/// Specifies the license under which the API is made available.
343#[derive(Clone, Debug, Deserialize, Serialize)]
344#[serde(rename_all = "camelCase")]
345pub struct License {
346 /// The license name used for the API. This field is required.
347 pub name: String,
348
349 /// An SPDX license identifier (e.g., "MIT", "Apache-2.0"). (OpenAPI v3.1+)
350 pub identifier: Option<String>,
351
352 /// A URL to the license. Must be a valid URL.
353 pub url: Option<String>
354}
355
356/// Server connectivity information.
357///
358/// Represents a server that provides connectivity to the target API.
359/// The URL may contain variables enclosed in curly braces which are substituted
360/// using values from the `variables` map.
361///
362/// # Example
363///
364/// ```rust
365/// use product_os_openapi::{Server, ServerVariable};
366/// use std::collections::BTreeMap;
367///
368/// let mut variables = BTreeMap::new();
369/// variables.insert("environment".to_owned(), ServerVariable {
370/// default: "production".to_owned(),
371/// enumeration: Some(vec!["production".to_owned(), "staging".to_owned()]),
372/// description: Some("Environment name".to_owned()),
373/// });
374///
375/// let server = Server {
376/// url: "https://{environment}.example.com".to_owned(),
377/// description: Some("Main API server".to_owned()),
378/// variables: Some(variables),
379/// };
380/// ```
381#[derive(Clone, Debug, Deserialize, Serialize)]
382#[serde(rename_all = "camelCase")]
383pub struct Server {
384 /// The URL to the target host. May contain variables in curly braces.
385 pub url: String,
386
387 /// An optional description of the host. CommonMark syntax may be used.
388 pub description: Option<String>,
389
390 /// A map of variable name to its value substitution information.
391 pub variables: Option<BTreeMap<String, ServerVariable>>
392}
393
394/// Variable substitution information for a Server URL.
395///
396/// Used to provide information about variables that can be substituted
397/// in a Server URL template.
398#[derive(Clone, Debug, Deserialize, Serialize)]
399#[serde(rename_all = "camelCase")]
400pub struct ServerVariable {
401 /// An optional enumeration of allowed values for this variable.
402 #[serde(rename = "enum")]
403 pub enumeration: Option<Vec<String>>,
404
405 /// The default value for substitution. This field is required.
406 pub default: String,
407
408 /// An optional description of the variable. CommonMark syntax may be used.
409 pub description: Option<String>
410}
411
412/// Reusable components for an OpenAPI specification.
413///
414/// This struct holds various reusable objects that can be referenced throughout
415/// the specification, reducing duplication and improving maintainability.
416#[derive(Clone, Debug, Deserialize, Serialize)]
417#[serde(rename_all = "camelCase")]
418pub struct Components {
419 /// Reusable Schema objects (data models).
420 pub schemas: Option<BTreeMap<String, Schema>>,
421
422 /// Reusable Response objects.
423 pub responses: Option<BTreeMap<String, Response>>,
424
425 /// Reusable Parameter objects.
426 pub parameters: Option<BTreeMap<String, Parameter>>,
427
428 /// Reusable Example objects.
429 pub examples: Option<BTreeMap<String, Example>>,
430
431 /// Reusable Request Body objects.
432 pub request_bodies: Option<BTreeMap<String, RequestBody>>,
433
434 /// Reusable Header objects.
435 pub headers: Option<BTreeMap<String, Header>>,
436
437 /// Reusable Security Scheme objects.
438 pub security_schemes: Option<BTreeMap<String, SecurityScheme>>,
439
440 /// Reusable Link objects.
441 pub links: Option<BTreeMap<String, Link>>,
442
443 /// Reusable Callback objects.
444 pub callbacks: Option<Callbacks>,
445
446 /// Reusable Path Item objects.
447 pub path_items: Option<BTreeMap<String, PathItem>>,
448}
449
450/// Describes a single API path and its operations.
451///
452/// A Path Item may contain operation objects for HTTP methods (GET, PUT, POST, etc.),
453/// or it may be a reference to another Path Item definition.
454///
455/// # Example
456///
457/// ```rust
458/// use product_os_openapi::{PathItem, Operation};
459/// use std::collections::BTreeMap;
460///
461/// let path_item = PathItem {
462/// reference: None,
463/// summary: Some("User operations".to_owned()),
464/// description: Some("Operations for managing users".to_owned()),
465/// get: Some(Operation {
466/// summary: Some("Get user".to_owned()),
467/// operation_id: Some("getUser".to_owned()),
468/// tags: Some(vec!["users".to_owned()]),
469/// description: None,
470/// external_docs: None,
471/// parameters: None,
472/// request_body: None,
473/// responses: None,
474/// callbacks: None,
475/// deprecated: None,
476/// security: None,
477/// servers: None,
478/// }),
479/// put: None,
480/// post: None,
481/// delete: None,
482/// options: None,
483/// head: None,
484/// patch: None,
485/// trace: None,
486/// servers: None,
487/// parameters: None,
488/// };
489/// ```
490#[derive(Clone, Debug, Deserialize, Serialize)]
491#[serde(rename_all = "camelCase")]
492pub struct PathItem {
493 /// Reference to another Path Item. When present, other fields are overridden.
494 #[serde(rename = "$ref")]
495 pub reference: Option<String>,
496
497 /// A short summary of the path item.
498 pub summary: Option<String>,
499
500 /// A detailed description of the path item. CommonMark syntax may be used.
501 pub description: Option<String>,
502
503 /// Definition of a GET operation on this path.
504 pub get: Option<Operation>,
505
506 /// Definition of a PUT operation on this path.
507 pub put: Option<Operation>,
508
509 /// Definition of a POST operation on this path.
510 pub post: Option<Operation>,
511
512 /// Definition of a DELETE operation on this path.
513 pub delete: Option<Operation>,
514
515 /// Definition of an OPTIONS operation on this path.
516 pub options: Option<Operation>,
517
518 /// Definition of a HEAD operation on this path.
519 pub head: Option<Operation>,
520
521 /// Definition of a PATCH operation on this path.
522 pub patch: Option<Operation>,
523
524 /// Definition of a TRACE operation on this path.
525 pub trace: Option<Operation>,
526
527 /// Alternative servers for operations in this path.
528 pub servers: Option<Vec<Server>>,
529
530 /// Parameters applicable to all operations in this path.
531 /// Can be overridden at the operation level.
532 pub parameters: Option<Vec<Parameter>>
533}
534
535
536/// JSON Schema data types supported by OpenAPI.
537///
538/// Represents the basic data types that can be used in schema definitions.
539///
540/// # Serialization
541///
542/// This enum serializes to lowercase strings matching the JSON Schema specification.
543///
544/// # Example
545///
546/// ```rust
547/// use product_os_openapi::SchemaType;
548///
549/// assert_eq!(SchemaType::String.to_string(), "string");
550/// assert_eq!(SchemaType::Integer.to_string(), "integer");
551/// assert_eq!(SchemaType::Array.to_string(), "array");
552/// ```
553#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
554#[serde(rename_all = "lowercase")]
555pub enum SchemaType {
556 /// JSON object type
557 Object,
558 /// Numeric type with decimals
559 Number,
560 /// Numeric type without decimals
561 Integer,
562 /// String type
563 String,
564 /// Boolean type (true/false)
565 Boolean,
566 /// Array type
567 Array
568}
569
570impl fmt::Display for SchemaType {
571 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
572 match self {
573 SchemaType::Object => write!(f, "object"),
574 SchemaType::Number => write!(f, "number"),
575 SchemaType::Integer => write!(f, "integer"),
576 SchemaType::String => write!(f, "string"),
577 SchemaType::Boolean => write!(f, "boolean"),
578 SchemaType::Array => write!(f, "array")
579 }
580 }
581}
582
583
584/// Parameter or schema location within an API operation.
585///
586/// Specifies where a parameter or schema property can be located in an HTTP request.
587#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
588#[serde(rename_all = "lowercase")]
589pub enum SchemaLocation {
590 /// In the URL path (e.g., `/users/{id}`)
591 Path,
592 /// In the request body
593 Body,
594 /// In the URL query string (e.g., `?limit=10`)
595 Query,
596 /// In an HTTP cookie
597 Cookie
598}
599
600
601/// JSON Schema definition for data models.
602///
603/// Defines the structure and constraints of data types used in the API.
604/// Can represent primitive types, objects, arrays, or references to other schemas.
605///
606/// # Example
607///
608/// ```rust
609/// use product_os_openapi::{Schema, SchemaType, SchemaProperty};
610/// use std::collections::BTreeMap;
611///
612/// let mut properties = BTreeMap::new();
613/// properties.insert("id".to_owned(), SchemaProperty {
614/// reference: None,
615/// description: Some("User ID".to_owned()),
616/// all_of: None,
617/// kind: Some(SchemaType::Integer),
618/// minimum: Some(1),
619/// items: None,
620/// min_items: None,
621/// unique_items: None,
622/// min_length: None,
623/// required: None,
624/// });
625///
626/// let schema = Schema {
627/// reference: None,
628/// title: Some("User".to_owned()),
629/// description: Some("User model".to_owned()),
630/// all_of: None,
631/// kind: Some(SchemaType::Object),
632/// format: None,
633/// properties: Some(properties),
634/// minimum: None,
635/// maximum: None,
636/// items: None,
637/// min_items: None,
638/// max_items: None,
639/// unique_items: None,
640/// min_length: None,
641/// max_length: None,
642/// required: Some(vec!["id".to_owned()]),
643/// discriminator: None,
644/// xml: None,
645/// external_docs: None,
646/// example: None,
647/// };
648/// ```
649#[derive(Clone, Debug, Deserialize, Serialize)]
650#[serde(rename_all = "camelCase")]
651pub struct Schema {
652 /// Reference to another schema definition. When present, most other fields are ignored.
653 #[serde(rename = "$ref")]
654 pub reference: Option<String>,
655
656 /// A title for the schema.
657 pub title: Option<String>,
658
659 /// A description of the schema. CommonMark syntax may be used.
660 pub description: Option<String>,
661
662 /// Composition of schemas using allOf (all schemas must match).
663 pub all_of: Option<Vec<Box<Schema>>>,
664
665 /// The data type of the schema.
666 #[serde(rename = "type")]
667 pub kind: Option<SchemaType>,
668
669 /// Additional format information (e.g., "email", "date-time", "uuid").
670 pub format: Option<String>,
671
672 /// Properties of an object schema. Maps property names to their schemas.
673 pub properties: Option<BTreeMap<String, SchemaProperty>>,
674
675 /// Minimum value for numeric types.
676 pub minimum: Option<u64>,
677
678 /// Maximum value for numeric types.
679 pub maximum: Option<u64>,
680
681 /// Schema for items in an array.
682 pub items: Option<Box<Schema>>,
683
684 /// Minimum number of items in an array.
685 pub min_items: Option<u64>,
686
687 /// Maximum number of items in an array.
688 pub max_items: Option<u64>,
689
690 /// Whether array items must be unique.
691 pub unique_items: Option<bool>,
692
693 /// Minimum length for string types.
694 pub min_length: Option<u64>,
695
696 /// Maximum length for string types.
697 pub max_length: Option<u64>,
698
699 /// List of required property names for object types.
700 pub required: Option<Vec<String>>,
701
702 /// Discriminator for polymorphism support.
703 pub discriminator: Option<Discriminator>,
704
705 /// XML metadata for XML serialization.
706 pub xml: Option<XML>,
707
708 /// Additional external documentation for this schema.
709 pub external_docs: Option<ExternalDocs>,
710
711 /// Example value for this schema.
712 pub example: Option<serde_json::Value>,
713}
714
715
716/// Property definition within a Schema.
717///
718/// Similar to Schema but simplified for use as object properties.
719#[derive(Clone, Debug, Deserialize, Serialize)]
720#[serde(rename_all = "camelCase")]
721pub struct SchemaProperty {
722 /// Reference to another schema definition.
723 #[serde(rename = "$ref")]
724 pub reference: Option<String>,
725
726 /// Description of the property. CommonMark syntax may be used.
727 pub description: Option<String>,
728
729 /// Composition of schemas using allOf.
730 pub all_of: Option<Vec<Box<SchemaProperty>>>,
731
732 /// The data type of the property.
733 #[serde(rename = "type")]
734 pub kind: Option<SchemaType>,
735
736 /// Minimum value for numeric types.
737 pub minimum: Option<u64>,
738
739 /// Schema for items if this property is an array.
740 pub items: Option<Box<Schema>>,
741
742 /// Minimum number of items if this property is an array.
743 pub min_items: Option<u64>,
744
745 /// Whether array items must be unique.
746 pub unique_items: Option<bool>,
747
748 /// Minimum length for string types.
749 pub min_length: Option<u64>,
750
751 /// List of required nested property names.
752 pub required: Option<Vec<String>>,
753}
754
755
756
757/// Discriminator for polymorphism support.
758///
759/// Used to differentiate between schemas in inheritance/polymorphism scenarios.
760#[derive(Clone, Debug, Deserialize, Serialize)]
761#[serde(rename_all = "camelCase")]
762pub struct Discriminator {
763 /// The name of the property that holds the discriminator value. This field is required.
764 pub property_name: String,
765
766 /// Mapping between payload values and schema names or references.
767 pub mapping: Option<BTreeMap<String, String>>
768}
769
770/// XML serialization metadata.
771///
772/// Provides information for XML representation of schema properties.
773#[derive(Clone, Debug, Deserialize, Serialize)]
774#[serde(rename_all = "camelCase")]
775pub struct XML {
776 /// Replaces the name of the element/attribute.
777 pub name: Option<String>,
778
779 /// The URI of the namespace definition. Must be an absolute URI.
780 pub namespace: Option<String>,
781
782 /// The prefix to be used for the name.
783 pub prefix: Option<String>,
784
785 /// Whether the property translates to an XML attribute (default: false).
786 pub attribute: Option<bool>,
787
788 /// Whether arrays are wrapped in an element (default: false).
789 pub wrapped: Option<bool>,
790}
791
792
793/// A single API operation on a path.
794///
795/// Describes a single operation (HTTP method) available on a path, including
796/// parameters, request body, responses, and security requirements.
797#[derive(Clone, Debug, Deserialize, Serialize)]
798#[serde(rename_all = "camelCase")]
799pub struct Operation {
800 /// Tags for logical grouping of operations.
801 pub tags: Option<Vec<String>>,
802
803 /// A short summary of the operation.
804 pub summary: Option<String>,
805
806 /// A detailed description of the operation. CommonMark syntax may be used.
807 pub description: Option<String>,
808
809 /// Additional external documentation for this operation.
810 pub external_docs: Option<ExternalDocs>,
811
812 /// Unique identifier for the operation. Should follow naming conventions.
813 pub operation_id: Option<String>,
814
815 /// Parameters applicable for this operation.
816 pub parameters: Option<Vec<Parameter>>,
817
818 /// The request body for this operation.
819 pub request_body: Option<RequestBody>,
820
821 /// Possible responses from this operation, keyed by HTTP status code or "default".
822 pub responses: Option<BTreeMap<String, Response>>,
823
824 /// Callbacks that may be initiated by the API provider.
825 pub callbacks: Option<BTreeMap<String, BTreeMap<String, PathItem>>>,
826
827 /// Whether this operation is deprecated (default: false).
828 pub deprecated: Option<bool>,
829
830 /// Security requirements for this operation. Overrides global security.
831 pub security: Option<Vec<BTreeMap<String, Vec<String>>>>,
832
833 /// Alternative server for this operation.
834 pub servers: Option<Server>,
835}
836
837
838/// Response from an API operation.
839///
840/// Describes a single response from an operation, including headers, content, and links.
841#[derive(Clone, Debug, Deserialize, Serialize)]
842#[serde(rename_all = "camelCase")]
843pub struct Response {
844 /// Reference to a response definition.
845 #[serde(rename = "$ref")]
846 pub reference: Option<String>,
847
848 /// Short summary of the response.
849 pub summary: Option<String>,
850
851 /// Description of the response. CommonMark syntax may be used.
852 pub description: Option<String>,
853
854 /// Response headers, keyed by header name.
855 pub headers: Option<BTreeMap<String, Header>>,
856
857 /// Response content, keyed by media type (e.g., "application/json").
858 pub content: Option<BTreeMap<String, MediaType>>,
859
860 /// Links to operations that can be followed from this response.
861 pub links: Option<BTreeMap<String, Link>>,
862
863 /// Schema for the response (Swagger v2 only).
864 pub schema: Option<Schema>,
865}
866
867/// Operation parameter.
868///
869/// Describes a single operation parameter that can be located in the path, query, header, or cookie.
870#[derive(Clone, Debug, Deserialize, Serialize)]
871#[serde(rename_all = "camelCase")]
872pub struct Parameter {
873 /// Reference to a parameter definition.
874 #[serde(rename = "$ref")]
875 pub reference: Option<String>,
876
877 /// Short summary of the parameter.
878 pub summary: Option<String>,
879
880 /// Description of the parameter. CommonMark syntax may be used.
881 pub description: Option<String>,
882
883 /// Name of the parameter. Required unless this is a reference.
884 pub name: Option<String>,
885
886 /// Location of the parameter: "query", "header", "path", or "cookie".
887 #[serde(rename = "in")]
888 pub location: Option<String>,
889
890 /// Whether the parameter is mandatory. Path parameters must be required.
891 pub required: Option<bool>,
892
893 /// Whether the parameter is deprecated (default: false).
894 pub deprecated: Option<bool>,
895
896 /// Whether empty-valued parameters are allowed (default: false).
897 pub allow_empty_value: Option<bool>,
898
899 /// Serialization style for the parameter value.
900 pub style: Option<String>,
901
902 /// Whether to generate separate parameters for array/object values.
903 pub explode: Option<bool>,
904
905 /// Whether to allow reserved characters without percent-encoding.
906 pub allow_reserved: Option<bool>,
907
908 /// Schema defining the parameter type.
909 pub schema: Option<Schema>,
910
911 /// Example value for the parameter.
912 pub example: Option<serde_json::Value>,
913
914 /// Multiple examples for the parameter.
915 pub examples: Option<BTreeMap<String, Example>>,
916
917 /// Content representation for complex parameters.
918 pub content: Option<BTreeMap<String, MediaType>>,
919}
920
921
922/// Example value for a parameter, request body, or response.
923#[derive(Clone, Debug, Deserialize, Serialize)]
924#[serde(rename_all = "camelCase")]
925pub struct Example {
926 /// Reference to an example definition.
927 #[serde(rename = "$ref")]
928 pub reference: Option<String>,
929
930 /// Short summary of the example.
931 pub summary: Option<String>,
932
933 /// Long description of the example. CommonMark syntax may be used.
934 pub description: Option<String>,
935
936 /// Embedded literal example value.
937 pub value: Option<serde_json::Value>,
938
939 /// URI pointing to an external example.
940 pub external_value: Option<String>
941}
942
943
944/// Request body for an operation.
945#[derive(Clone, Debug, Deserialize, Serialize)]
946#[serde(rename_all = "camelCase")]
947pub struct RequestBody {
948 /// Reference to a request body definition.
949 #[serde(rename = "$ref")]
950 pub reference: Option<String>,
951
952 /// Short summary of the request body.
953 pub summary: Option<String>,
954
955 /// Description of the request body. CommonMark syntax may be used.
956 pub description: Option<String>,
957
958 /// Content of the request body, keyed by media type. This field is required.
959 pub content: BTreeMap<String, MediaType>,
960
961 /// Whether the request body is required (default: false).
962 pub required: Option<bool>,
963}
964
965/// HTTP header definition.
966#[derive(Clone, Debug, Deserialize, Serialize)]
967#[serde(rename_all = "camelCase")]
968pub struct Header {
969 /// Reference to a header definition.
970 #[serde(rename = "$ref")]
971 pub reference: Option<String>,
972
973 /// Short summary of the header.
974 pub summary: Option<String>,
975
976 /// Description of the header. CommonMark syntax may be used.
977 pub description: Option<String>,
978
979 /// Whether the header is required (default: false).
980 pub required: Option<bool>,
981
982 /// Whether the header is deprecated (default: false).
983 pub deprecated: Option<bool>,
984
985 /// Whether empty values are allowed (default: false).
986 pub allow_empty_value: Option<bool>,
987
988 /// Serialization style for the header value.
989 pub style: Option<String>,
990
991 /// Whether to generate separate parameters for array/object values.
992 pub explode: Option<bool>,
993
994 /// Whether to allow reserved characters.
995 pub allow_reserved: Option<bool>,
996
997 /// Schema defining the header type.
998 pub schema: Option<Schema>,
999
1000 /// Example value for the header.
1001 pub example: Option<serde_json::Value>,
1002
1003 /// Multiple examples for the header.
1004 pub examples: Option<BTreeMap<String, Example>>,
1005
1006 /// Content representation for the header.
1007 pub content: Option<BTreeMap<String, MediaType>>,
1008}
1009
1010/// Media type and schema for request/response content.
1011#[derive(Clone, Debug, Deserialize, Serialize)]
1012#[serde(rename_all = "camelCase")]
1013pub struct MediaType {
1014 /// Schema defining the content structure.
1015 pub schema: Option<Schema>,
1016
1017 /// Example of the media type content.
1018 pub example: Option<serde_json::Value>,
1019
1020 /// Multiple examples of the media type content.
1021 pub examples: Option<BTreeMap<String, Example>>,
1022
1023 /// Encoding information for specific properties (multipart/form-data, application/x-www-form-urlencoded).
1024 pub encoding: Option<BTreeMap<String, Encoding>>,
1025}
1026
1027/// Property encoding information for multipart and form-urlencoded request bodies.
1028#[derive(Clone, Debug, Deserialize, Serialize)]
1029#[serde(rename_all = "camelCase")]
1030pub struct Encoding {
1031 /// Content-Type for encoding a specific property.
1032 pub content_type: Option<String>,
1033
1034 /// Additional headers for the property.
1035 pub headers: Option<BTreeMap<String, Header>>,
1036
1037 /// Serialization style for the property value.
1038 pub style: Option<String>,
1039
1040 /// Whether to generate separate parameters for array/object values.
1041 pub explode: Option<bool>,
1042
1043 /// Whether to allow reserved characters.
1044 pub allow_reserved: Option<bool>
1045}
1046
1047/// Security scheme definition.
1048#[derive(Clone, Debug, Deserialize, Serialize)]
1049#[serde(rename_all = "camelCase")]
1050pub struct SecurityScheme {
1051 /// Reference to a security scheme definition.
1052 #[serde(rename = "$ref")]
1053 pub reference: Option<String>,
1054
1055 /// Short summary of the security scheme.
1056 pub summary: Option<String>,
1057
1058 /// Description of the security scheme. CommonMark syntax may be used.
1059 pub description: Option<String>,
1060
1061 /// Type of security scheme: "apiKey", "http", "mutualTLS", "oauth2", or "openIdConnect". Required.
1062 #[serde(rename = "type")]
1063 pub kind: String,
1064
1065 /// Name of the API key header, query, or cookie parameter (for apiKey type).
1066 pub api_key: Option<String>,
1067
1068 /// Location of the API key: "query", "header", or "cookie" (for apiKey type).
1069 #[serde(rename = "in")]
1070 pub location: Option<String>,
1071
1072 /// HTTP authorization scheme name (for http type). Required for http type.
1073 pub scheme: String,
1074
1075 /// Hint for bearer token format, e.g., "JWT" (for http bearer type).
1076 pub bearer_format: Option<String>,
1077
1078 /// OAuth2 flow configurations (for oauth2 type). Required for oauth2 type.
1079 pub flows: Option<OAuthFlows>,
1080
1081 /// OpenID Connect URL for OAuth2 configuration discovery (for openIdConnect type). Required for openIdConnect type.
1082 pub open_id_connect_url: Option<String>,
1083}
1084
1085/// OAuth2 flow configurations.
1086#[derive(Clone, Debug, Deserialize, Serialize)]
1087#[serde(rename_all = "camelCase")]
1088pub struct OAuthFlows {
1089 /// OAuth2 implicit flow configuration.
1090 pub implicit: Option<OAuthFlow>,
1091
1092 /// OAuth2 resource owner password flow configuration.
1093 pub password: Option<OAuthFlow>,
1094
1095 /// OAuth2 client credentials flow configuration.
1096 pub client_credentials: Option<OAuthFlow>,
1097
1098 /// OAuth2 authorization code flow configuration.
1099 pub authorization_code: Option<OAuthFlow>,
1100}
1101
1102/// Single OAuth2 flow configuration.
1103#[derive(Clone, Debug, Deserialize, Serialize)]
1104#[serde(rename_all = "camelCase")]
1105pub struct OAuthFlow {
1106 /// Authorization URL (required for implicit and authorizationCode flows).
1107 pub authorization_url: String,
1108
1109 /// Token URL (required for password, clientCredentials, and authorizationCode flows).
1110 pub token_url: String,
1111
1112 /// Refresh token URL.
1113 pub refresh_url: Option<String>,
1114
1115 /// Available scopes. Maps scope names to descriptions. Required.
1116 pub scopes: BTreeMap<String, String>
1117}
1118
1119/// Link to an operation that can be followed from a response.
1120#[derive(Clone, Debug, Deserialize, Serialize)]
1121#[serde(rename_all = "camelCase")]
1122pub struct Link {
1123 /// Reference to a link definition.
1124 #[serde(rename = "$ref")]
1125 pub reference: Option<String>,
1126
1127 /// Short summary of the link.
1128 pub summary: Option<String>,
1129
1130 /// Description of the link. CommonMark syntax may be used.
1131 pub description: Option<String>,
1132
1133 /// Relative or absolute URI reference to an operation.
1134 pub operation_ref: Option<String>,
1135
1136 /// Name of an existing operation (mutually exclusive with operation_ref).
1137 pub operation_id: Option<String>,
1138
1139 /// Parameters to pass to the linked operation.
1140 pub parameters: Option<BTreeMap<String, serde_json::Value>>,
1141
1142 /// Request body to use when calling the linked operation.
1143 pub request_body: Option<serde_json::Value>,
1144
1145 /// Server to use for the linked operation.
1146 pub server: Option<Server>,
1147}
1148
1149/// Tag for grouping operations.
1150#[derive(Clone, Debug, Deserialize, Serialize)]
1151#[serde(rename_all = "camelCase")]
1152pub struct Tag {
1153 /// Name of the tag. Required.
1154 pub name: String,
1155
1156 /// Description of the tag. CommonMark syntax may be used.
1157 pub description: Option<String>,
1158
1159 /// Additional external documentation for the tag.
1160 pub external_docs: Option<ExternalDocs>,
1161}
1162
1163
1164/// External documentation reference.
1165#[derive(Clone, Debug, Deserialize, Serialize)]
1166#[serde(rename_all = "camelCase")]
1167pub struct ExternalDocs {
1168 /// URL to the external documentation. Required.
1169 pub url: String,
1170
1171 /// Description of the external documentation. CommonMark syntax may be used.
1172 pub description: Option<String>
1173}
1174
1175/// Reference to a reusable component.
1176#[derive(Clone, Debug, Deserialize, Serialize)]
1177#[serde(rename_all = "camelCase")]
1178pub struct Reference {
1179 /// The reference identifier URI. Required.
1180 #[serde(rename = "$ref")]
1181 pub reference: Option<String>,
1182
1183 /// Short summary overriding the referenced component's summary.
1184 pub summary: Option<String>,
1185
1186 /// Description overriding the referenced component's description. CommonMark syntax may be used.
1187 pub description: Option<String>
1188}
1189
1190// Implementation methods for convenience and validation
1191impl ProductOSOpenAPI {
1192 /// Checks if this is an OpenAPI v3.x specification.
1193 ///
1194 /// Returns `true` if the `openapi` field is present, indicating this is an OpenAPI v3 spec.
1195 ///
1196 /// # Example
1197 ///
1198 /// ```rust
1199 /// use product_os_openapi::{ProductOSOpenAPI, Info};
1200 ///
1201 /// let spec = ProductOSOpenAPI {
1202 /// openapi: Some("3.0.0".to_owned()),
1203 /// info: Info {
1204 /// title: "Test".to_owned(),
1205 /// version: "1.0.0".to_owned(),
1206 /// summary: None,
1207 /// description: None,
1208 /// terms_of_service: None,
1209 /// contact: None,
1210 /// license: None,
1211 /// },
1212 /// json_schema_dialect: None,
1213 /// servers: None,
1214 /// paths: None,
1215 /// webhooks: None,
1216 /// components: None,
1217 /// definitions: None,
1218 /// security: None,
1219 /// tags: None,
1220 /// external_docs: None,
1221 /// swagger: None,
1222 /// host: None,
1223 /// base_path: None,
1224 /// schemes: None,
1225 /// consumes: None,
1226 /// produces: None,
1227 ///};
1228 ///
1229 /// assert!(spec.is_openapi_v3());
1230 /// ```
1231 pub fn is_openapi_v3(&self) -> bool {
1232 self.openapi.is_some()
1233 }
1234
1235 /// Checks if this is a Swagger v2.0 specification.
1236 ///
1237 /// Returns `true` if the `swagger` field is present, indicating this is a Swagger v2 spec.
1238 ///
1239 /// # Example
1240 ///
1241 /// ```rust
1242 /// use product_os_openapi::{ProductOSOpenAPI, Info};
1243 ///
1244 /// let spec = ProductOSOpenAPI {
1245 /// swagger: Some("2.0".to_owned()),
1246 /// info: Info {
1247 /// title: "Test".to_owned(),
1248 /// version: "1.0.0".to_owned(),
1249 /// summary: None,
1250 /// description: None,
1251 /// terms_of_service: None,
1252 /// contact: None,
1253 /// license: None,
1254 /// },
1255 /// openapi: None,
1256 /// json_schema_dialect: None,
1257 /// servers: None,
1258 /// paths: None,
1259 /// webhooks: None,
1260 /// components: None,
1261 /// definitions: None,
1262 /// security: None,
1263 /// tags: None,
1264 /// external_docs: None,
1265 /// host: None,
1266 /// base_path: None,
1267 /// schemes: None,
1268 /// consumes: None,
1269 /// produces: None,
1270 /// };
1271 ///
1272 /// assert!(spec.is_swagger_v2());
1273 /// ```
1274 pub fn is_swagger_v2(&self) -> bool {
1275 self.swagger.is_some()
1276 }
1277
1278 /// Gets the specification version string.
1279 ///
1280 /// Returns the OpenAPI version (e.g., "3.0.0") or Swagger version (e.g., "2.0").
1281 ///
1282 /// # Example
1283 ///
1284 /// ```rust
1285 /// use product_os_openapi::{ProductOSOpenAPI, Info};
1286 ///
1287 /// let spec = ProductOSOpenAPI {
1288 /// openapi: Some("3.1.0".to_owned()),
1289 /// info: Info {
1290 /// title: "Test".to_owned(),
1291 /// version: "1.0.0".to_owned(),
1292 /// summary: None,
1293 /// description: None,
1294 /// terms_of_service: None,
1295 /// contact: None,
1296 /// license: None,
1297 /// },
1298 /// json_schema_dialect: None,
1299 /// servers: None,
1300 /// paths: None,
1301 /// webhooks: None,
1302 /// components: None,
1303 /// definitions: None,
1304 /// security: None,
1305 /// tags: None,
1306 /// external_docs: None,
1307 /// swagger: None,
1308 /// host: None,
1309 /// base_path: None,
1310 /// schemes: None,
1311 /// consumes: None,
1312 /// produces: None,
1313 /// };
1314 ///
1315 /// assert_eq!(spec.version(), Some("3.1.0"));
1316 /// ```
1317 pub fn version(&self) -> Option<&str> {
1318 self.openapi.as_deref().or(self.swagger.as_deref())
1319 }
1320}
1321