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}