Skip to content

Commit 2da0193

Browse files
authored
feat: add support for server-only extractors (#5086)
1 parent 552b553 commit 2da0193

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

examples/07-fullstack/server_functions.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,12 @@ async fn anonymous() -> Result<String> {
282282
/// This is less preferred over the `#[get]`/`#[post]` syntax but is still functional for backwards
283283
/// compatibility. Previously, only the `#[server]` attribute was available, but as of Dioxus 0.7,
284284
/// the `#[get]`/`#[post]` attributes are preferred for new code.
285-
#[server(prefix = "/api/custom", endpoint = "my_anonymous")]
285+
///
286+
/// You can also use server-only extractors here as well, provided they come after the configuration.
287+
#[server(prefix = "/api/custom", endpoint = "my_anonymous", headers: dioxus_fullstack::HeaderMap)]
286288
async fn custom_anonymous() -> Result<String> {
287-
Ok("Hello from a custom anonymous server function!".to_string())
289+
Ok(format!(
290+
"Hello from a custom anonymous server function! -> {:#?}",
291+
headers
292+
))
288293
}

packages/fullstack-macro/src/lib.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ pub fn server(attr: proc_macro::TokenStream, mut item: TokenStream) -> TokenStre
109109
query_params: vec![],
110110
route_lit: args.fn_path,
111111
oapi_options: None,
112-
server_args: Default::default(),
112+
server_args: args.server_args,
113113
prefix: Some(prefix),
114114
_input_encoding: args.input,
115115
_output_encoding: args.output,
@@ -1505,6 +1505,9 @@ struct ServerFnArgs {
15051505
/// The protocol to use for the server function implementation.
15061506
protocol: Option<Type>,
15071507
builtin_encoding: bool,
1508+
/// Server-only extractors (e.g., headers: HeaderMap, cookies: Cookies).
1509+
/// These are arguments that exist purely on the server side.
1510+
server_args: Punctuated<FnArg, Comma>,
15081511
}
15091512

15101513
impl Parse for ServerFnArgs {
@@ -1529,7 +1532,18 @@ impl Parse for ServerFnArgs {
15291532
let mut use_key_and_value = false;
15301533
let mut arg_pos = 0;
15311534

1535+
// Server-only extractors (key: Type pattern)
1536+
// These come after config options (key = value pattern)
1537+
// Example: #[server(endpoint = "/api/chat", headers: HeaderMap, cookies: Cookies)]
1538+
let mut server_args: Punctuated<FnArg, Comma> = Punctuated::new();
1539+
15321540
while !stream.is_empty() {
1541+
// Check if this looks like an extractor (Ident : Type)
1542+
// If so, break out to parse extractors - they must come last
1543+
if stream.peek(Ident) && stream.peek2(Token![:]) {
1544+
break;
1545+
}
1546+
15331547
arg_pos += 1;
15341548
let lookahead = stream.lookahead1();
15351549
if lookahead.peek(Ident) {
@@ -1698,6 +1712,20 @@ impl Parse for ServerFnArgs {
16981712
}
16991713
}
17001714

1715+
// Now parse any remaining extractors (key: Type pattern)
1716+
while !stream.is_empty() {
1717+
if stream.peek(Ident) && stream.peek2(Token![:]) {
1718+
server_args.push_value(stream.parse::<FnArg>()?);
1719+
if stream.peek(Comma) {
1720+
server_args.push_punct(stream.parse::<Comma>()?);
1721+
} else {
1722+
break;
1723+
}
1724+
} else {
1725+
break;
1726+
}
1727+
}
1728+
17011729
// parse legacy encoding into input/output
17021730
let mut builtin_encoding = false;
17031731
if let Some(encoding) = encoding {
@@ -1740,6 +1768,7 @@ impl Parse for ServerFnArgs {
17401768
impl_from,
17411769
impl_deref,
17421770
protocol,
1771+
server_args,
17431772
})
17441773
}
17451774
}

0 commit comments

Comments
 (0)