Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"gotcha_macro",
"examples/*"
]
exclude = ["examples/clouldflare-worker"]
default-members = ["gotcha", "gotcha_macro"]

[workspace.dependencies]
Expand Down
6 changes: 6 additions & 0 deletions examples/openapi/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use gotcha::{api, ConfigWrapper, GotchaApp, GotchaContext, GotchaRouter, Json, Path, Schematic};
use serde::{Deserialize, Serialize};

mod test_skip;

#[derive(Schematic, Serialize, Deserialize, Debug)]
pub struct ResponseWrapper<T: Schematic> {
pub code: i32,
Expand Down Expand Up @@ -100,6 +102,10 @@ impl GotchaApp for App {
.get("/pets/:pet_id", get_pet)
.put("/pets/:pet_id", update_pet_info)
.put("/pets/:pet_id/address/:address_id", update_pet_address_detail)
// Test skip functionality
.post("/test/skip-json/:key_id", test_skip::test_skip_json)
.post("/test/skip-query/:key_id", test_skip::test_skip_query)
.post("/test/no-skip/:key_id", test_skip::test_no_skip)
}

async fn state<'a, 'b>(&'a self, _config: &'b ConfigWrapper<Self::Config>) -> Result<Self::State, Box<dyn std::error::Error>> {
Expand Down
63 changes: 63 additions & 0 deletions examples/openapi/src/test_skip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use gotcha::{api, Json, Path, Query, Schematic};
use serde::{Deserialize, Serialize};

#[derive(Schematic, Serialize, Deserialize)]
pub struct ApiKey {
pub id: u32,
pub name: String,
}

#[derive(Schematic, Serialize, Deserialize)]
pub struct FilterParams {
pub active: Option<bool>,
pub limit: Option<u32>,
}

#[derive(Schematic, Serialize, Deserialize)]
pub struct CreateApiKeyRequest {
pub name: String,
pub description: String,
}

/// Test endpoint with skipped Json body parameter - only Path parameter should appear in OpenAPI
#[api(id = "test_skip_json", group = "test_skip")]
pub async fn test_skip_json(
Path(key_id): Path<u32>,
#[api(skip)] Json(body): Json<CreateApiKeyRequest>, // This will be skipped in OpenAPI
) -> Json<ApiKey> {
// The Json(body) parameter should be skipped in OpenAPI docs
// Only Path(key_id) should appear in the generated OpenAPI
Json(ApiKey {
id: key_id,
name: body.name,
})
}

/// Test endpoint with skipped Query parameter - only Path and Json should appear in OpenAPI
#[api(id = "test_skip_query", group = "test_skip")]
pub async fn test_skip_query(
Path(key_id): Path<u32>,
#[api(skip)] Query(filter): Query<FilterParams>, // This will be skipped in OpenAPI
Json(body): Json<CreateApiKeyRequest>,
) -> Json<ApiKey> {
// The Query(filter) parameter should be skipped in OpenAPI docs
// Path(key_id) and Json(body) should appear in the generated OpenAPI
Json(ApiKey {
id: key_id,
name: format!("{} (limit: {:?})", body.name, filter.limit),
})
}

/// Test endpoint without skip - all parameters visible in OpenAPI
#[api(id = "test_no_skip", group = "test_skip")]
pub async fn test_no_skip(
Path(key_id): Path<u32>,
Query(filter): Query<FilterParams>,
Json(body): Json<CreateApiKeyRequest>,
) -> Json<ApiKey> {
// All parameters should appear in OpenAPI docs
Json(ApiKey {
id: key_id,
name: format!("{} (limit: {:?})", body.name, filter.limit),
})
}
2 changes: 1 addition & 1 deletion gotcha/src/openapi/schematic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub trait Schematic {

/// ParameterProvider is a trait that defines the value which can be used as a parameter.
pub trait ParameterProvider {
fn generate(url: String) -> Either<Vec<Parameter>, RequestBody> {
fn generate(_url: String) -> Either<Vec<Parameter>, RequestBody> {
Either::Left(vec![])
}
}
Expand Down
1 change: 1 addition & 0 deletions gotcha/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ impl<State: Clone + Send + Sync + 'static> GotchaRouter<State> {
/// let router: GotchaRouter<()> = GotchaRouter::default()
/// .method_route("/", MethodFilter::GET, hello_world);
/// ```
#[allow(unused_mut)]
pub fn method_route<H, T>(mut self, path: &str, method: MethodFilter, handler: H) -> Self
where
H: Handler<T, State>,
Expand Down
24 changes: 8 additions & 16 deletions gotcha_macro/src/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,15 @@ pub(crate) fn request_handler(args: TokenStream, input_stream: TokenStream) -> T
.flat_map(|param| match param {
FnArg::Receiver(_) => None,
FnArg::Typed(typed) => {
// TODO: typed parse attribute

// Check if the parameter has the #[api(skip)] attribute
let should_skip = typed.attrs.iter().any(|attr| {
if let Ok(meta) = attr.parse_meta() {
if let syn::Meta::List(meta_list) = meta {
if meta_list.path.is_ident("api") {
return meta_list.nested.iter().any(|nested_meta| {
if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = nested_meta {
path.is_ident("skip")
} else {
false
}
});
}
}
if attr.path.is_ident("api") {
// Parse the attribute tokens to check for "skip"
let tokens = attr.tokens.to_string();
tokens.contains("skip")
} else {
false
}
false
});

if should_skip {
Expand Down Expand Up @@ -98,7 +89,8 @@ pub(crate) fn request_handler(args: TokenStream, input_stream: TokenStream) -> T

input.sig.inputs.iter_mut().for_each(|param| {
if let FnArg::Typed(typed) = param {
typed.attrs = vec![];
// Remove only the #[api(...)] attributes, keep others
typed.attrs.retain(|attr| !attr.path.is_ident("api"));
}
});

Expand Down
1 change: 0 additions & 1 deletion gotcha_macro/src/schematic/named_struct.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
use syn::GenericParam;

use crate::schematic::ParameterStructFieldOpt;
use crate::utils::AttributesExt;
Expand Down
Loading