Renvoyer des données

Définir le modèle

Dans models.rs

#[derive(Serialize, Debug)]
pub struct Review {
    pub product_id: i32,
    pub reviewer: String,
    pub review: String,
}

Dans lib.rs

mod models;

Traduire avec les entrées / sorties

Dans reviews.rs

use models;

Définir la structure JSON de sortie

#[derive(Debug, Serialize)]
pub struct Product {
    pub id: i32,
    pub reviews: Vec<Review>,
}

#[derive(Debug, Serialize)]
pub struct Review {
    pub reviewer: String,
    pub text: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rating: Option<Rating>,
}

#[derive(Debug, Serialize)]
pub struct Rating {
    pub stars: i32,
    pub color: Color,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Color {
    Blue,
    Yellow,
    Red,
}

Convertir le modèle en sortie

pub fn rating_nb_to_rating(rating: i32) -> Rating {
    Rating {
        stars: rating,
        color: match rating {
            1 => Color::Red,
            2 | 3 => Color::Yellow,
            _ => Color::Blue,
        },
    }
}

pub fn reviews_with_ratings(
    reviews: Vec<models::Review>,
    ratings: HashMap<String, i32>,
) -> Vec<Review> {
    reviews
        .iter()
        .map(|review| {
            let reviewer = review.reviewer.clone();
            Review {
                rating: ratings.get(&reviewer).map(|&r| rating_nb_to_rating(r)),
                reviewer: reviewer,
                text: review.review.clone(),
            }
        })
        .collect()
}

Renvoyer la réponse

let ratings = HashMap::new();
let reviews = vec![];

let build_response_from_ratings = move |ratings| {
    futures::future::result({
        // build the response
        let product = Product {
            id: product_id,
            reviews: reviews_with_ratings(reviews, ratings),
        };
        // return a 200 response with the reviews as json
        Ok(HttpResponse::Ok().json(product))
    })
};

build_response_from_ratings(ratings).responder()

Définir la structure JSON en entrée

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct NewReview {
    reviewer: String,
    text: String,
    rating: i32,
}

Convertir l'entrée en modèle

let review_to_save = models::Review {
    product_id: product_id as i32,
    reviewer: review.reviewer.clone(),
    review: review.text.clone(),
};

Renvoyer la réponse

futures::future::result({
    Ok(HttpResponse::Ok().json(review.clone()))
}).responder()

Résultat

Récupérer les reviews d'un product donne une liste vide

curl localhost:9080/reviews/0 -i
HTTP/1.1 200 OK
content-length: 21
content-type: application/json
date: Thu, 19 Apr 2018 21:59:21 GMT

{"id":0,"reviews":[]}

Poster une review la renvoie telle quelle

curl localhost:9080/reviews/0 -i -H 'Content-Type: application/json' -d '{"reviewer":"moi","rating":3,"text":"mon avis"}'
HTTP/1.1 200 OK
content-length: 47
content-type: application/json
date: Thu, 19 Apr 2018 22:00:57 GMT

{"reviewer":"moi","text":"mon avis","rating":3}

Poster un JSON invalide répond une erreur 400 et un message dans les logs

curl localhost:9080/reviews/0 -i -H 'Content-Type: application/json' -d '{"reviewer":"moi","rating":3}'
HTTP/1.1 400 Bad Request
content-length: 0
date: Thu, 19 Apr 2018 22:01:54 GMT
{"msg":"Error occured during request handling: Json deserialize error: missing field `text` at line 1 column 29","level":"WARN","ts":"2018-04-20T00:01:55.287447+02:00","logger":"app"}