Search code examples
csvrustserdeactix-web

How to deserialize actix web form data and serialize it into csv file?


How to deserialize actix_web Form data and serialize it into csv file? Is it possible to use one struct for it? How to cover csv error scenario? I'm trying to save form data x-www-form-urlencoded into csv file in my first Rust program but this language is soo strict comparing to Ruby;) How could I move code responsible for saving to csv to dedicated function?

extern crate csv;
#[macro_use]
extern crate serde_derive;
use actix_web::{middleware, web, App, HttpResponse, HttpServer, Result};
use serde::{Deserialize, Serialize};
use std::io;

#[derive(Serialize, Deserialize)]
struct FormData {
    email: String,
    fullname: String,
    message: String,
}

async fn contact(form: web::Form<FormData>) -> Result<String> {
    let mut wtr = csv::Writer::from_writer(io::stdout());
    wtr.serialize(form)?;
    wtr.flush()?;

    Ok(format!("Hello {}!", form.fullname))
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(web::resource("/contact").route(web::post().to(contact)))
    })
    .bind("127.0.0.1:8000")?
    .run()
    .await
}

I've got following errors:

error[E0277]: the trait bound `actix_web::types::form::Form<FormData>: _IMPL_DESERIALIZE_FOR_FormData::_serde::Serialize` is not satisfied
  --> src/main.rs:46:19
   |
46 |     wtr.serialize(form)?;
   |                   ^^^^ the trait `_IMPL_DESERIALIZE_FOR_FormData::_serde::Serialize` is not implemented for `actix_web::types::form::Form<FormData>`

error[E0277]: the trait bound `csv::Error: actix_http::error::ResponseError` is not satisfied
  --> src/main.rs:46:24
   |
46 |     wtr.serialize(form)?;
   |                        ^ the trait `actix_http::error::ResponseError` is not implemented for `csv::Error`
   |
   = note: required because of the requirements on the impl of `std::convert::From<csv::Error>` for `actix_http::error::Error`
   = note: required by `std::convert::From::from`

error: aborting due to 2 previous errors

Used libs:

[dependencies]
actix-web = "2.0.0"
actix-rt = "1.0.0"
serde = "1.0"
serde_derive = "1.0.110"
csv = "1.1"

Solution

  • You needed to get the inner struct of the web::form data.

    pub async fn contact(form: web::Form<FormData>) -> HttpResponse<Body> {
      let mut wtr = csv::Writer::from_writer(io::stdout());
      wtr.serialize(form.into_inner());
      wtr.flush();
    
      HttpResponse::Ok().body("".to_string())
    }