conduit_json_parser/
lib.rs1#![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}