Search code examples
postrustwebassemblyserdeactix-web

Web assembly sending faulty Json body that the server cannot deserialize


Problem

Webassembly is sending a post req to an actix web server, but actix web says it cannot deserialize the json body.

In terminal (for actix web) you can see the error message of

Failed to deserialize Json from payload. Request path: /api
Error in response: Deserialize(Error("expected value", line: 1, column: 2))

And in javascript console

Response { url: "http://localhost:8080/api", status: 400, statusText: "Bad Request", /* ... */ }

I have tried sending the same request using curl, and it worked. So there is clearly something wrong with the request the wasm is sending, but I'm not sure what

curl --header "Content-Type: application/json" \                                                                                                                         :(
  --request POST \
  --data '{"field1": "one", "field2": "two", "field3": "three"}' \
  http://localhost:8080/api

Here's the code sending the request (web assembly)

let _ = window
    .fetch_with_str_and_init("/api", &RequestInit::new().method("POST").headers(&headers).body(Some(&serde_wasm_bindgen::to_value(&req).unwrap())))
    .then(&ok);

and here's the server receiving the request

#[post("/api")]
async fn api(body: Json<Req>) -> String {
    format!("{body:?}")
}

#[derive(Debug, Deserialize)]
struct Req {
    field1: String,
    field2: String,
    field3: String,
}

Here's how to reproduce the issue:

repo

git clone https://github.com/Siriusmart/dummy-repo-for-asking-stackoverflow

wasm-pack build --target web wasm to recompile the web assembly first

then cargo run to start the server

visit http://localhost:8080 to see the site with wasm.

When the button is pressed, there should be output to the js console, saying that its a bad request, at the same time there will also be an error message in the actix web console.

The goal is to make it so that the wasm actually sends a good request to the server.


Solution

  • serde_wasm_bindgen serializes Req to a JS object, and that is what fetch() gets. I think it calls toString() on it, resulting it [object Object] (not entirely sure), but this is definitely not sending JSON.

    You need to serialize the data to JSON yourself, for example via serde_json then call JsValue: From<String> or by serializing it to JS object with serde_wasm_bindgen then calling JSON.stringify() on it.