Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server Function taking struct with empty Vec fails to deserialize #1741

Closed
smessmer opened this issue Sep 16, 2023 · 6 comments
Closed

Server Function taking struct with empty Vec fails to deserialize #1741

smessmer opened this issue Sep 16, 2023 · 6 comments

Comments

@smessmer
Copy link

Describe the bug

If a server function takes a MyData struct that contains a Vec, and then that server function is called with an empty Vec, it fails deserialization saying the whole field is missing.

#[derive(Serialize, Deserialize)]
struct Entry {
  id: i32,
}

#[derive(Serialize, Deserialize)]
struct MyData {
   // ... other fields
   some_list: Vec<Entry>,
}

#[server]
fn my_server_fun(data: MyData) {
}

#[component]
fn MyComponent() -> impl IntoView {
  let call_server_fn = create_action(move |_: &()| { my_server_fun(MyData{some_list: vec![]}) });
  view! {
    <button on:click=move || call_server_fun.dispatch() >{"Call server fun"}</button>
  }
}

Fails with:

{"Deserialization":"missing field `some_list`"}

Looking at the data sent over the network, it seems that it uses Multipart Encoding and sends the parameters as:

data[some_list][0]: ...
data[some_list][1]: ...

and when the list is empty, it just doesn't contain any entries for it. This is likely the cause of the issue.

Changing the encoding of the server function to Cbor works, so it's specific to the Url encoding.

Leptos Dependencies

leptos = { version = "^0.5.0-rc1", features = ["nightly"] }
leptos_axum = { version = "^0.5.0-rc1", optional = true }
leptos_meta = { version = "^0.5.0-rc1", features = ["nightly"] }
leptos_router = { version = "^0.5.0-rc1", features = ["nightly"] }

To Reproduce

  1. Call a server function as described above with an empty list
  2. Observe failure

Expected behavior
Server function is correctly called and deserializes its arguments

@dpytaylo
Copy link
Contributor

I have encountered with the same problem. A empty vector cause this error 😥

@chrisp60
Copy link
Contributor

chrisp60 commented Sep 16, 2023

Some encodings have no method for displaying an empty list of items. Annotate your struct definition with #[serde(default)]. This will cause serde to assume a missing field is to be replaced with the Default::default implementation of it's type. @smessmer

#[derive(Serialize, Deserialize)]
struct MyData {
   #[serde(default)]
   some_list: Vec<Entry>,
}

For what it is worth, this is expected behavior of serde. #[serde(default)] can be annotated on the entire item if many fields could be "empty".

@gbj gbj added bug Something isn't working and removed bug Something isn't working labels Sep 18, 2023
@gbj
Copy link
Collaborator

gbj commented Sep 18, 2023

I missed the fact that this was a nested struct originally. Yes I think @ChristopherPerry6060 has the correct answer here: add #[serde(default)] on the struct field or the whole struct.

@dpytaylo You say you've encountered the same issue: Is that similarly on a nested struct like this?

(I say "nested" because the server functions arguments are, themselves, built into a struct.)

It's also possible this is serde_qs specific behavior that makes encoding and decoding not perfectly reversible. (serde_qs is what's used for this server function URL encoding.)

@dpytaylo
Copy link
Contributor

I missed the fact that this was a nested struct originally. Yes I think @ChristopherPerry6060 has the correct answer here: add #[serde(default)] on the struct field or the whole struct.

@dpytaylo You say you've encountered the same issue: Is that similarly on a nested struct like this?

(I say "nested" because the server functions arguments are, themselves, built into a struct.)

It's also possible this is serde_qs specific behavior that makes encoding and decoding not perfectly reversible. (serde_qs is what's used for this server function URL encoding.)

No, I use just a vector:

#[server(SendChatMessage, "/api")]
pub async fn send_chat_message(messages: Vec<String>, new_message: String) -> Result<String, ServerFnError> {
    
}

@gbj
Copy link
Collaborator

gbj commented Sep 18, 2023

Yeah so ultimately it's just this known issue with serde_qs: samscott89/serde_qs#78

I guess we could add an attribute to the server fn macro that passes through #[serde(default)].

@gbj
Copy link
Collaborator

gbj commented Sep 21, 2023

This is closed by #1762: You can add #[server(default)] to any argument to a server function to indicate that it should use the default value, if absent.

@gbj gbj closed this as completed Sep 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants