Skip to main content

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