Skip to main content

reinhardt_views/
openapi.rs

1//! OpenAPI schema generation
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// OpenAPI 3.0 specification document.
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct OpenAPISpec {
9	/// OpenAPI specification version (e.g., `"3.0.0"`).
10	pub openapi: String,
11	/// Metadata about the API.
12	pub info: Info,
13	/// Available API paths and their operations.
14	pub paths: HashMap<String, PathItem>,
15	/// Reusable schema components.
16	pub components: Option<Components>,
17}
18
19impl OpenAPISpec {
20	/// Create a new `OpenAPISpec` with the given info and OpenAPI version 3.0.0.
21	pub fn new(info: Info) -> Self {
22		Self {
23			openapi: "3.0.0".to_string(),
24			info,
25			paths: HashMap::new(),
26			components: None,
27		}
28	}
29}
30
31/// API metadata including title, version, and description.
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct Info {
34	/// Title of the API.
35	pub title: String,
36	/// Version of the API.
37	pub version: String,
38	/// Optional description of the API.
39	pub description: Option<String>,
40}
41
42impl Info {
43	/// Create a new `Info` with the given title and version.
44	pub fn new(title: String, version: String) -> Self {
45		Self {
46			title,
47			version,
48			description: None,
49		}
50	}
51}
52
53/// Operations available on a single API path.
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct PathItem {
56	/// GET operation.
57	pub get: Option<Operation>,
58	/// POST operation.
59	pub post: Option<Operation>,
60	/// PUT operation.
61	pub put: Option<Operation>,
62	/// DELETE operation.
63	pub delete: Option<Operation>,
64	/// PATCH operation.
65	pub patch: Option<Operation>,
66}
67
68impl PathItem {
69	/// Create a new empty `PathItem` with no operations.
70	pub fn new() -> Self {
71		Self {
72			get: None,
73			post: None,
74			put: None,
75			delete: None,
76			patch: None,
77		}
78	}
79}
80
81impl Default for PathItem {
82	fn default() -> Self {
83		Self::new()
84	}
85}
86
87/// A single API operation (e.g., GET /users).
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct Operation {
90	/// Short summary of the operation.
91	pub summary: Option<String>,
92	/// Detailed description of the operation.
93	pub description: Option<String>,
94	/// Parameters accepted by the operation.
95	pub parameters: Vec<Parameter>,
96	/// Possible responses keyed by HTTP status code.
97	pub responses: HashMap<String, Response>,
98}
99
100impl Operation {
101	/// Create a new empty `Operation`.
102	pub fn new() -> Self {
103		Self {
104			summary: None,
105			description: None,
106			parameters: Vec::new(),
107			responses: HashMap::new(),
108		}
109	}
110}
111
112impl Default for Operation {
113	fn default() -> Self {
114		Self::new()
115	}
116}
117
118/// An API operation parameter.
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct Parameter {
121	/// Name of the parameter.
122	pub name: String,
123	/// Where the parameter is located (query, header, path, or cookie).
124	pub location: ParameterLocation,
125	/// Whether the parameter is required.
126	pub required: bool,
127	/// Schema describing the parameter type.
128	pub schema: Schema,
129}
130
131impl Parameter {
132	/// Create a new `Parameter` with the given name and location.
133	pub fn new(name: String, location: ParameterLocation) -> Self {
134		Self {
135			name,
136			location,
137			required: false,
138			schema: Schema::new("string".to_string()),
139		}
140	}
141}
142
143/// Location of an API parameter.
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
145#[serde(rename_all = "lowercase")]
146pub enum ParameterLocation {
147	/// Query string parameter.
148	Query,
149	/// HTTP header parameter.
150	Header,
151	/// URL path parameter.
152	Path,
153	/// Cookie parameter.
154	Cookie,
155}
156
157/// An API response definition.
158#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct Response {
160	/// Description of the response.
161	pub description: String,
162	/// Response content keyed by media type (e.g., `"application/json"`).
163	pub content: Option<HashMap<String, MediaType>>,
164}
165
166impl Response {
167	/// Create a new `Response` with the given description.
168	pub fn new(description: String) -> Self {
169		Self {
170			description,
171			content: None,
172		}
173	}
174}
175
176/// Media type definition with its associated schema.
177#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct MediaType {
179	/// Schema describing the media type content.
180	pub schema: Schema,
181}
182
183impl MediaType {
184	/// Create a new `MediaType` with the given schema.
185	pub fn new(schema: Schema) -> Self {
186		Self { schema }
187	}
188}
189
190/// JSON Schema definition for API types.
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct Schema {
193	/// The data type (e.g., `"string"`, `"object"`, `"integer"`).
194	#[serde(rename = "type")]
195	pub schema_type: String,
196	/// Nested property schemas for object types.
197	pub properties: Option<HashMap<String, Schema>>,
198}
199
200impl Schema {
201	/// Create a new `Schema` with the given type.
202	pub fn new(schema_type: String) -> Self {
203		Self {
204			schema_type,
205			properties: None,
206		}
207	}
208}
209
210/// Reusable OpenAPI components container.
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct Components {
213	/// Named schema definitions.
214	pub schemas: HashMap<String, Schema>,
215}
216
217impl Components {
218	/// Create a new empty `Components`.
219	pub fn new() -> Self {
220		Self {
221			schemas: HashMap::new(),
222		}
223	}
224}
225
226impl Default for Components {
227	fn default() -> Self {
228		Self::new()
229	}
230}
231
232/// Generator for producing JSON Schema objects.
233pub struct SchemaGenerator;
234
235impl SchemaGenerator {
236	/// Create a new `SchemaGenerator`.
237	pub fn new() -> Self {
238		Self
239	}
240
241	/// Generate a default object schema.
242	pub fn generate(&self) -> Schema {
243		Schema::new("object".to_string())
244	}
245}
246
247impl Default for SchemaGenerator {
248	fn default() -> Self {
249		Self::new()
250	}
251}
252
253/// Information about a single API endpoint.
254#[derive(Debug, Clone)]
255pub struct EndpointInfo {
256	/// URL path of the endpoint.
257	pub path: String,
258	/// HTTP method (e.g., `"GET"`, `"POST"`).
259	pub method: String,
260	/// Operation metadata for this endpoint.
261	pub operation: Operation,
262}
263
264impl EndpointInfo {
265	/// Create a new `EndpointInfo` with the given path and method.
266	pub fn new(path: String, method: String) -> Self {
267		Self {
268			path,
269			method,
270			operation: Operation::new(),
271		}
272	}
273}