conduit_json_parser/
lib.rs

1#![cfg_attr(test, deny(warnings))]
2
3extern crate rustc_serialize;
4
5extern crate conduit;
6extern crate conduit_middleware as middleware;
7extern crate conduit_utils as utils;
8
9use std::any::Any;
10use std::error::Error;
11use std::io::prelude::*;
12use std::marker;
13use rustc_serialize::Decodable;
14use rustc_serialize::json::{self, Json};
15
16use conduit::Request;
17use middleware::Middleware;
18
19pub struct BodyReader<T> {
20    _marker: marker::PhantomData<fn() -> T>,
21}
22
23impl<T: Decodable + Any> BodyReader<T> {
24    pub fn new() -> BodyReader<T> {
25        BodyReader { _marker: marker::PhantomData }
26    }
27}
28
29impl<T: Decodable + Any> Middleware for BodyReader<T> {
30    fn before(&self, req: &mut Request) -> Result<(), Box<Error+Send>> {
31        let json: T = try!(decode::<T>(req.body()));
32
33        req.mut_extensions().insert(json);
34        Ok(())
35    }
36}
37
38#[allow(trivial_casts)]
39fn decode<T: Decodable>(reader: &mut Read) -> Result<T, Box<Error+Send>> {
40    let j = try!(Json::from_reader(reader).map_err(|e| Box::new(e) as Box<Error+Send>));
41    let mut decoder = json::Decoder::new(j);
42    Decodable::decode(&mut decoder).map_err(|e| Box::new(e) as Box<Error+Send>)
43}
44
45pub fn json_params<'a, T: Decodable + Any>(req: &'a Request) -> Option<&'a T> {
46    req.extensions().find::<T>()
47}
48
49#[cfg(test)]
50mod tests {
51    extern crate conduit_test;
52
53    use {json_params, BodyReader};
54
55    use std::collections::HashMap;
56    use std::io::{self, Cursor};
57    use rustc_serialize::json;
58
59    use conduit::{Request, Response, Handler, Method};
60    use middleware::MiddlewareBuilder;
61
62    #[derive(PartialEq, RustcDecodable, RustcEncodable, Debug)]
63    struct Person {
64        name: String,
65        location: String
66    }
67
68    fn handler(req: &mut Request) -> io::Result<Response> {
69        let person = json_params::<Person>(req);
70        let out = person.map(|p| json::encode(p).unwrap()).expect("No JSON");
71
72        Ok(Response {
73            status: (200, "OK"),
74            headers: HashMap::new(),
75            body: Box::new(Cursor::new(out.into_bytes()))
76        })
77    }
78
79    #[test]
80    fn test_body_params() {
81        let mut req = conduit_test::MockRequest::new(Method::Get, "/");
82        req.with_body(br#"{ "name": "Alex Crichton", "location": "San Francisco" }"#);
83
84        let mut middleware = MiddlewareBuilder::new(handler);
85        middleware.add(BodyReader::<Person>::new());
86
87        let mut res = middleware.call(&mut req).ok().expect("No response");
88        let person = super::decode::<Person>(&mut *res.body).ok().expect("No JSON response");
89        assert_eq!(person, Person {
90            name: "Alex Crichton".to_string(),
91            location: "San Francisco".to_string()
92        });
93    }
94}