Search code examples
rustactix-web

Share memory data by REST parameters in Rust


my "main" file

mod router;
mod student;

use std::sync::Arc;

use crate::router::init_router;
use crate::router::Memory;

use actix_web::{App, HttpServer};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv::dotenv().ok();
    let repo = Arc::new(Memory::repository());
    let host = std::env::var("SERVER.HOST").unwrap_or("127.0.0.1".to_string());
    let port = std::env::var("SERVER.PORT").unwrap_or("8080".to_string());
    let url = format!("{}:{}", host, port);
    println!("url: {}", &url);
    
    HttpServer::new(move || {
        App::new()
            .data(repo.clone())     // shared
            .configure(init_router)
    })
    .bind(&url)?
    .run()
    .await
}

my file: "router.rs"

use std::sync::Arc;

use crate::student::Student;
use actix_web::{get, web, HttpResponse, Responder};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Memory {
    pub students: Vec<Student>,
}

impl Memory {
    fn new() -> Self {
        Memory {
            students: Vec::new(),
        }
    }

    pub fn repository() -> Self{
        Self {
            students: vec![
                {Student::new("1".to_string(), "Daniel".to_string(), 19)},
                {Student::new("2".to_string(), "Lucia".to_string(), 17)},
                {Student::new("3".to_string(), "Juan".to_string(), 14)}
            ]
        }
    }
}

#[get("/studen/list/all")]
async fn list_all(repo: web::Data<Arc<Memory>>) -> impl Responder {
    HttpResponse::Ok().json(repo)
}

pub fn init_router(config: &mut web::ServiceConfig) {
    config.service(list_all);
}

and my file: "student.rs"

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Student{
    pub id: String,
    pub nombre: String,
    pub calificacion: u32,
}

impl Student{
    pub fn new(id: String, nombre: String, calificacion: u32) -> Self{
        Self{id, nombre, calificacion}
    }
}

so I want to show all students in a json via the following path: 127.0.0.1:3000/student/list/all
but i have the following error

| HttpResponse::Ok().json(repo)
| ^^^^ the trait Serialize is not implemented for Data<Arc<Memory>>

I still can't pass this data by parameter of a GET method, I need a little help please to display it in json. It is necessary because later I will need this data by parameter to add or remove.


Solution

  • (Note that you typed #[get("/studen/list/all")] instead of #[get("/student/list/all")] in your original code.)

    You don't want to serialize the Data<Arc<Memory>> to JSON, you only want to serialize the Memory. To do so, you can dereference the Data<Arc<Memory>> to get an Arc<Arc<Memory>>, then dereference the Arcs twice to get a Memory. Then, you add a reference as to not require cloning the resulting Memory. So, you replace

    HttpResponse::Ok().json(repo)
    

    with

    HttpResponse::Ok().json(&***repo)
    

    However, Data is already a wrapper around an Arc, so no Arc<Memory> in the is required. If you want to edit the Memory eventually, you'll have to add a Mutex inside. So, you'll have to obtain a lock on repo before serializing it.