Skip to content

Commit a0b6041

Browse files
committed
Revert "!"
This reverts commit 9bba035.
1 parent 9bba035 commit a0b6041

20 files changed

Lines changed: 36 additions & 1459 deletions

File tree

Cargo.lock

Lines changed: 9 additions & 487 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ members = [
44
"crates/rustapi-rs",
55
"crates/rustapi-core",
66
"crates/rustapi-macros",
7-
"crates/rustapi-validate",
8-
"crates/rustapi-openapi",
97
"examples/hello-world",
108
]
119

@@ -50,17 +48,9 @@ pin-project-lite = "0.2"
5048
# Proc macros
5149
syn = { version = "2.0", features = ["full", "parsing", "extra-traits"] }
5250
quote = "1.0"
53-
54-
# Validation
55-
validator = { version = "0.18", features = ["derive"] }
5651
proc-macro2 = "1.0"
5752
inventory = "0.3"
5853

59-
# OpenAPI
60-
utoipa = { version = "5", features = ["preserve_order"] }
61-
6254
# Internal crates
6355
rustapi-core = { path = "crates/rustapi-core" }
6456
rustapi-macros = { path = "crates/rustapi-macros" }
65-
rustapi-openapi = { path = "crates/rustapi-openapi" }
66-
rustapi-validate = { path = "crates/rustapi-validate" }

crates/rustapi-core/Cargo.toml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,6 @@ serde = { workspace = true }
2727
serde_json = { workspace = true }
2828
serde_urlencoded = "0.7"
2929

30-
# Validation
31-
validator = { workspace = true }
32-
33-
# OpenAPI
34-
rustapi-openapi = { workspace = true }
35-
3630
# Middleware
3731
tower = { workspace = true }
3832
tower-service = { workspace = true }

crates/rustapi-core/src/app.rs

Lines changed: 5 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
//! RustApi application builder
22
33
use crate::error::Result;
4-
use crate::router::{get, MethodRouter, Router};
4+
use crate::router::{MethodRouter, Router};
55
use crate::server::Server;
6-
use crate::response::{Html, Response};
7-
use crate::extract::Json;
8-
use rustapi_openapi::{OpenApiDoc, swagger_ui_html};
9-
use std::sync::Arc;
106
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
117

128
/// Main application builder for RustAPI
@@ -28,8 +24,6 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilte
2824
/// ```
2925
pub struct RustApi {
3026
router: Router,
31-
openapi: Option<OpenApiDoc>,
32-
docs_path: Option<String>,
3327
}
3428

3529
impl RustApi {
@@ -45,8 +39,6 @@ impl RustApi {
4539

4640
Self {
4741
router: Router::new(),
48-
openapi: None,
49-
docs_path: None,
5042
}
5143
}
5244

@@ -108,40 +100,16 @@ impl RustApi {
108100
self
109101
}
110102

111-
/// Configure OpenAPI documentation
112-
///
113-
/// # Example
114-
///
115-
/// ```rust,ignore
116-
/// use rustapi_openapi::OpenApiDoc;
117-
///
118-
/// RustApi::new()
119-
/// .openapi(OpenApiDoc::new("My API", "1.0.0")
120-
/// .description("A sample API")
121-
/// .server("http://localhost:8080"))
122-
/// ```
123-
pub fn openapi(mut self, doc: OpenApiDoc) -> Self {
124-
self.openapi = Some(doc);
125-
self
126-
}
127-
128103
/// Enable Swagger UI at the specified path
129104
///
130-
/// Also enables `/openapi.json` endpoint automatically.
131-
///
132105
/// # Example
133106
///
134107
/// ```rust,ignore
135108
/// RustApi::new()
136-
/// .openapi(OpenApiDoc::new("My API", "1.0.0"))
137-
/// .docs("/docs") // Swagger UI at /docs, spec at /openapi.json
109+
/// .docs("/docs") // Swagger UI at /docs
138110
/// ```
139-
pub fn docs(mut self, path: &str) -> Self {
140-
self.docs_path = Some(path.to_string());
141-
// Create default OpenAPI doc if not set
142-
if self.openapi.is_none() {
143-
self.openapi = Some(OpenApiDoc::new("RustAPI", "1.0.0"));
144-
}
111+
pub fn docs(self, _path: &str) -> Self {
112+
// TODO: Implement OpenAPI + Swagger UI
145113
self
146114
}
147115

@@ -155,42 +123,7 @@ impl RustApi {
155123
/// .run("127.0.0.1:8080")
156124
/// .await
157125
/// ```
158-
pub async fn run(mut self, addr: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
159-
// Add OpenAPI endpoints if configured
160-
if let Some(doc) = self.openapi.take() {
161-
let doc = Arc::new(doc);
162-
let docs_path = self.docs_path.take();
163-
164-
// Add /openapi.json endpoint
165-
let doc_for_json = doc.clone();
166-
self.router = self.router.route(
167-
"/openapi.json",
168-
get(move || {
169-
let doc = doc_for_json.clone();
170-
async move {
171-
OpenApiJsonResponse(doc.to_json())
172-
}
173-
}),
174-
);
175-
176-
// Add Swagger UI endpoint if docs path is set
177-
if let Some(path) = docs_path {
178-
let title = doc.title().to_string();
179-
self.router = self.router.route(
180-
&path,
181-
get(move || {
182-
let title = title.clone();
183-
async move {
184-
Html(swagger_ui_html("/openapi.json", &title))
185-
}
186-
}),
187-
);
188-
tracing::info!("📚 Swagger UI available at http://{}{}", addr, path);
189-
}
190-
191-
tracing::info!("📄 OpenAPI spec at http://{}/openapi.json", addr);
192-
}
193-
126+
pub async fn run(self, addr: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
194127
let server = Server::new(self.router);
195128
server.run(addr).await
196129
}
@@ -206,20 +139,3 @@ impl Default for RustApi {
206139
Self::new()
207140
}
208141
}
209-
210-
/// Response type for OpenAPI JSON
211-
struct OpenApiJsonResponse(String);
212-
213-
impl crate::response::IntoResponse for OpenApiJsonResponse {
214-
fn into_response(self) -> Response {
215-
use bytes::Bytes;
216-
use http::{header, StatusCode};
217-
use http_body_util::Full;
218-
219-
http::Response::builder()
220-
.status(StatusCode::OK)
221-
.header(header::CONTENT_TYPE, "application/json")
222-
.body(Full::new(Bytes::from(self.0)))
223-
.unwrap()
224-
}
225-
}

crates/rustapi-core/src/error.rs

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
use http::StatusCode;
44
use serde::Serialize;
5-
use std::collections::HashMap;
65
use std::fmt;
76

87
/// Result type alias for RustAPI operations
@@ -34,36 +33,6 @@ pub struct FieldError {
3433
pub code: String,
3534
/// Human-readable message
3635
pub message: String,
37-
/// Optional parameters (e.g., min/max values)
38-
#[serde(skip_serializing_if = "Option::is_none")]
39-
pub params: Option<HashMap<String, serde_json::Value>>,
40-
}
41-
42-
impl FieldError {
43-
/// Create a new field error
44-
pub fn new(field: impl Into<String>, code: impl Into<String>, message: impl Into<String>) -> Self {
45-
Self {
46-
field: field.into(),
47-
code: code.into(),
48-
message: message.into(),
49-
params: None,
50-
}
51-
}
52-
53-
/// Create a field error with parameters
54-
pub fn with_params(
55-
field: impl Into<String>,
56-
code: impl Into<String>,
57-
message: impl Into<String>,
58-
params: HashMap<String, serde_json::Value>,
59-
) -> Self {
60-
Self {
61-
field: field.into(),
62-
code: code.into(),
63-
message: message.into(),
64-
params: Some(params),
65-
}
66-
}
6736
}
6837

6938
impl ApiError {
@@ -119,43 +88,6 @@ impl ApiError {
11988
Self::new(StatusCode::INTERNAL_SERVER_ERROR, "internal_error", message)
12089
}
12190

122-
/// Create from validator::ValidationErrors
123-
pub fn from_validation_errors(errors: validator::ValidationErrors) -> Self {
124-
let mut field_errors = Vec::new();
125-
126-
for (field, error_kinds) in errors.field_errors() {
127-
for error in error_kinds {
128-
let code = error.code.to_string();
129-
let message = error
130-
.message
131-
.as_ref()
132-
.map(|m| m.to_string())
133-
.unwrap_or_else(|| format!("Validation failed for field '{}'", field));
134-
135-
let params = if error.params.is_empty() {
136-
None
137-
} else {
138-
let mut map = HashMap::new();
139-
for (key, value) in &error.params {
140-
if let Ok(json_value) = serde_json::to_value(value) {
141-
map.insert(key.to_string(), json_value);
142-
}
143-
}
144-
Some(map)
145-
};
146-
147-
field_errors.push(FieldError {
148-
field: field.to_string(),
149-
code,
150-
message,
151-
params,
152-
});
153-
}
154-
}
155-
156-
Self::validation(field_errors)
157-
}
158-
15991
/// Add internal details (for logging, hidden from response in prod)
16092
pub fn with_internal(mut self, details: impl Into<String>) -> Self {
16193
self.internal = Some(details.into());

crates/rustapi-core/src/extract.rs

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use serde::Serialize;
1313
use std::future::Future;
1414
use std::ops::{Deref, DerefMut};
1515
use std::str::FromStr;
16-
use validator::Validate;
1716

1817
/// Trait for extracting data from request parts (headers, path, query)
1918
///
@@ -288,80 +287,4 @@ impl_from_request_parts_for_primitives!(
288287
String
289288
);
290289

291-
/// Validated JSON body extractor
292-
///
293-
/// Parses the request body as JSON, deserializes into type `T`,
294-
/// and validates using the `validator` crate.
295-
/// Returns 422 Unprocessable Entity on validation failure.
296-
///
297-
/// # Example
298-
///
299-
/// ```rust,ignore
300-
/// use validator::Validate;
301-
///
302-
/// #[derive(Deserialize, Validate)]
303-
/// struct CreateUser {
304-
/// #[validate(email)]
305-
/// email: String,
306-
/// #[validate(length(min = 3, max = 50))]
307-
/// name: String,
308-
/// }
309-
///
310-
/// async fn create_user(ValidatedJson(body): ValidatedJson<CreateUser>) -> impl IntoResponse {
311-
/// // body is already deserialized AND validated
312-
/// }
313-
/// ```
314-
#[derive(Debug, Clone, Copy, Default)]
315-
pub struct ValidatedJson<T>(pub T);
316-
317-
impl<T: DeserializeOwned + Validate + Send> FromRequest for ValidatedJson<T> {
318-
async fn from_request(req: &mut Request) -> Result<Self> {
319-
let body = req.take_body().ok_or_else(|| {
320-
ApiError::internal("Body already consumed")
321-
})?;
322-
323-
let value: T = serde_json::from_slice(&body)?;
324-
325-
// Validate the deserialized value
326-
value.validate().map_err(|e| ApiError::from_validation_errors(e))?;
327-
328-
Ok(ValidatedJson(value))
329-
}
330-
}
331-
332-
impl<T> Deref for ValidatedJson<T> {
333-
type Target = T;
334-
335-
fn deref(&self) -> &Self::Target {
336-
&self.0
337-
}
338-
}
339-
340-
impl<T> DerefMut for ValidatedJson<T> {
341-
fn deref_mut(&mut self) -> &mut Self::Target {
342-
&mut self.0
343-
}
344-
}
345-
346-
impl<T> From<T> for ValidatedJson<T> {
347-
fn from(value: T) -> Self {
348-
ValidatedJson(value)
349-
}
350-
}
351-
352-
// IntoResponse for ValidatedJson - same as Json
353-
impl<T: Serialize> IntoResponse for ValidatedJson<T> {
354-
fn into_response(self) -> crate::response::Response {
355-
match serde_json::to_vec(&self.0) {
356-
Ok(body) => http::Response::builder()
357-
.status(StatusCode::OK)
358-
.header(header::CONTENT_TYPE, "application/json")
359-
.body(Full::new(Bytes::from(body)))
360-
.unwrap(),
361-
Err(err) => ApiError::internal(format!("Failed to serialize response: {}", err))
362-
.into_response(),
363-
}
364-
}
365-
}
366-
367290
// Re-export Json from response for extraction (they share the type)

crates/rustapi-core/src/lib.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,9 @@ mod server;
1515

1616
// Public API
1717
pub use app::RustApi;
18-
pub use error::{ApiError, FieldError, Result};
19-
pub use extract::{Body, FromRequest, FromRequestParts, Json, Path, Query, State, ValidatedJson};
18+
pub use error::{ApiError, Result};
19+
pub use extract::{Body, FromRequest, FromRequestParts, Json, Path, Query, State};
2020
pub use handler::{Handler, HandlerService};
2121
pub use request::Request;
22-
pub use response::{created, json, no_content, text, Created, Html, IntoResponse, NoContent, Redirect, Response};
22+
pub use response::{Created, Html, IntoResponse, NoContent, Redirect, Response};
2323
pub use router::{delete, get, patch, post, put, MethodRouter, Router};
24-
25-
// Re-export validator traits for users
26-
pub use validator::Validate;
27-
28-
// Re-export OpenAPI types
29-
pub use rustapi_openapi::OpenApiDoc;

0 commit comments

Comments
 (0)