omni_schema/
lib.rs

1//! # omni-schema
2//!
3//! **Universal Schema Generator for Rust** - One source of truth, multiple outputs.
4//!
5//! `omni-schema` generates multiple schema formats from a single Rust struct/enum
6//! definition using derive macros. Define your types once, export to JSON Schema,
7//! OpenAPI, GraphQL, Protocol Buffers, TypeScript, and Avro.
8//!
9//! ## Quick Start
10//!
11//! Add `omni-schema` to your `Cargo.toml`:
12//!
13//! ```toml
14//! [dependencies]
15//! omni-schema = { version = "0.1", features = ["all-formats"] }
16//! ```
17//!
18//! Then use the `Schema` derive macro:
19//!
20//! ```rust,ignore
21//! use omni_schema::Schema;
22//! use std::collections::HashMap;
23//!
24//! #[derive(Schema)]
25//! #[schema(description = "A user in the system")]
26//! pub struct User {
27//!     #[schema(description = "Unique identifier")]
28//!     pub id: u64,
29//!
30//!     #[schema(min_length = 1, max_length = 100)]
31//!     pub name: String,
32//!
33//!     #[schema(format = "email")]
34//!     pub email: String,
35//!
36//!     pub tags: Vec<String>,
37//! }
38//!
39//! #[derive(Schema)]
40//! pub enum Status {
41//!     Active,
42//!     Inactive,
43//!     Suspended { reason: String },
44//! }
45//! ```
46//!
47//! Generate schemas:
48//!
49//! ```rust,ignore
50//! use omni_schema::prelude::*;
51//!
52//! // Generate JSON Schema
53//! let json_schema = User::json_schema();
54//!
55//! // Generate TypeScript types
56//! let typescript = User::typescript_type();
57//!
58//! // Generate GraphQL SDL
59//! let graphql = User::graphql_sdl();
60//!
61//! // Generate Protocol Buffers
62//! let proto = User::proto_definition();
63//! ```
64//!
65//! ## Batch Export with Registry
66//!
67//! For exporting multiple types together:
68//!
69//! ```rust,ignore
70//! use omni_schema::{Schema, SchemaRegistry};
71//!
72//! let registry = SchemaRegistry::new()
73//!     .register::<User>()
74//!     .register::<Status>()
75//!     .with_title("My API")
76//!     .with_version("1.0.0");
77//!
78//! // Export to files
79//! registry.export_json_schema("./schemas/json/").unwrap();
80//! registry.export_typescript("./schemas/types.ts").unwrap();
81//! registry.export_graphql("./schemas/schema.graphql").unwrap();
82//! registry.export_proto("./schemas/models.proto").unwrap();
83//! ```
84//!
85//! ## Feature Flags
86//!
87//! - `json-schema` - JSON Schema generation (default)
88//! - `openapi` - OpenAPI 3.1 generation
89//! - `graphql` - GraphQL SDL generation
90//! - `protobuf` - Protocol Buffers generation
91//! - `typescript` - TypeScript type generation
92//! - `avro` - Apache Avro schema generation
93//! - `all-formats` - All format generators
94//! - `uuid-support` - UUID type support
95//! - `chrono-support` - DateTime type support
96//! - `url-support` - URL type support
97//! - `serde-compat` - Serde attribute compatibility
98//! - `full` - Everything enabled
99
100pub use omni_schema_derive::Schema;
101
102pub use omni_schema_core::{
103    Schema as SchemaImpl,
104    SchemaRegistry,
105    SchemaError, SchemaResult,
106    types::{
107        EnumDefinition, EnumRepresentation, EnumVariant, FieldDefinition,
108        NewtypeDefinition, PrimitiveType, SchemaDefinition, SchemaType,
109        StructDefinition, StructField, TypeReference, VariantData,
110    },
111    attributes::{
112        EnumAttribute, FieldAttribute, RenameRule, SchemaAttributes,
113        TypeAttribute, VariantAttribute,
114    },
115    ExternalSchema, FlattenableSchema,
116};
117
118/// Format-specific generators for advanced usage.
119pub mod formats {
120
121    #[cfg(feature = "json-schema")]
122    pub use omni_schema_core::formats::json_schema;
123
124    #[cfg(feature = "openapi")]
125    pub use omni_schema_core::formats::openapi;
126
127    #[cfg(feature = "graphql")]
128    pub use omni_schema_core::formats::graphql;
129
130    #[cfg(feature = "protobuf")]
131    pub use omni_schema_core::formats::protobuf;
132
133    #[cfg(feature = "typescript")]
134    pub use omni_schema_core::formats::typescript;
135
136    #[cfg(feature = "avro")]
137    pub use omni_schema_core::formats::avro;
138
139    pub use omni_schema_core::formats::format_ids;
140    pub use omni_schema_core::formats::utils;
141}
142
143pub use omni_schema_core::registry::RegistryConfig;
144
145#[cfg(feature = "uuid-support")]
146pub use uuid;
147
148#[cfg(feature = "chrono-support")]
149pub use chrono;
150
151#[cfg(feature = "url-support")]
152pub use url;
153
154#[cfg(feature = "serde-compat")]
155pub use serde;
156
157pub use serde_json;
158
159/// Prelude module for convenient imports.
160///
161/// ```rust,ignore
162/// use omni_schema::prelude::*;
163/// ```
164pub mod prelude {
165    pub use super::Schema;
166    pub use omni_schema_core::{Schema as SchemaImpl, SchemaRegistry};
167
168    #[cfg(feature = "json-schema")]
169    pub use omni_schema_core::formats::json_schema;
170
171    #[cfg(feature = "typescript")]
172    pub use omni_schema_core::formats::typescript;
173
174    #[cfg(feature = "graphql")]
175    pub use omni_schema_core::formats::graphql;
176
177    #[cfg(feature = "protobuf")]
178    pub use omni_schema_core::formats::protobuf;
179
180    #[cfg(feature = "openapi")]
181    pub use omni_schema_core::formats::openapi;
182
183    #[cfg(feature = "avro")]
184    pub use omni_schema_core::formats::avro;
185}
186
187#[cfg(test)]
188mod tests {
189    use super::*;
190
191    #[test]
192    fn test_schema_definition_creation() {
193        let def = SchemaDefinition::new(
194            "TestType",
195            SchemaType::Primitive(PrimitiveType::String),
196        )
197        .with_description("A test type");
198
199        assert_eq!(def.name, "TestType");
200        assert!(def.description.is_some());
201    }
202
203    #[test]
204    fn test_registry_creation() {
205        let registry = SchemaRegistry::new()
206            .with_title("Test API")
207            .with_version("1.0.0");
208
209        assert_eq!(registry.config().title, Some("Test API".to_string()));
210        assert_eq!(registry.config().version, Some("1.0.0".to_string()));
211    }
212
213    #[test]
214    fn test_struct_definition() {
215        let struct_def = StructDefinition::new()
216            .with_field(
217                "name",
218                StructField::new(
219                    SchemaType::Primitive(PrimitiveType::String),
220                    "name",
221                )
222                .with_description("The name field"),
223            );
224
225        assert_eq!(struct_def.fields.len(), 1);
226        assert!(struct_def.fields.contains_key("name"));
227    }
228
229    #[test]
230    fn test_enum_definition() {
231        let enum_def = EnumDefinition::new(EnumRepresentation::External)
232            .with_variant(EnumVariant::unit("Active"))
233            .with_variant(EnumVariant::unit("Inactive"));
234
235        assert_eq!(enum_def.variants.len(), 2);
236        assert!(enum_def.is_simple_enum());
237    }
238}