Repository: graphql-rust/juniper (language: rust)

Issue:
Drop rustc-serialize support
According to [Rust release milestone predictions](https://internals.rust-lang.org/t/rust-release-milestone-predictions/4591?u=dtolnay), rustc-serialize is scheduled to be deprecated in next month's beta release of Rust.

This would be a good time to let us know if there is any functionality you require from Serde before that happens.


Discussion / hints:
If @mhallin  is interested, I could work on a PR for removing rustc-serialize support from the next release.
@theduke  Sorry, but I stole this out from underneath you :stuck_out_tongue_closed_eyes: as I am trying to remove the duplicate code I would most likely need to write for #40 if both rustc_serialization and serde were supported. 
Hmm.

I really don't know what to say, except that I'm disillusioned with life,  incredibly disappointed, and I will never open Github again.

Ever.
Ok, I'm over it. :joy: 

Fix patch:
diff --git a/.travis.yml b/.travis.yml
index 67aad4abd..55bd8f511 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,8 +7,8 @@ rust:
   - nightly
 
   # The two most recent stable releases before "stable"
-  - 1.13.0
-  - 1.14.0
+  - 1.15.0
+  - 1.16.0
 
 matrix:
   allow_failures:
diff --git a/Cargo.toml b/Cargo.toml
index da46c251f..9600688a5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,15 +16,18 @@ harness = false
 path = "benches/bench.rs"
 
 [features]
-default = ["rustc-serialize"]
+default = ["serde", "serde_json"]
 nightly = []
-iron-handlers = ["iron", "rustc-serialize"]
+iron-handlers = ["iron", "default", "serde_derive", "urlencoded"]
 expose-test-schema = []
 
 [dependencies]
-rustc-serialize = { version = "^0.3.19", optional = true }
 iron = { version = "^0.5.1", optional = true }
 serde = { version = "^0.9.1", optional = true }
+serde_json = {version ="^0.9.1", optional = true }
+serde_derive = {version="^0.9.1", optional = true }
+urlencoded = {version="0.5", optional=true}
+
 
 [dev-dependencies]
 iron = "^0.5.1"
diff --git a/examples/server.rs b/examples/server.rs
index e4ef3cbed..9aa31107e 100644
--- a/examples/server.rs
+++ b/examples/server.rs
@@ -1,7 +1,7 @@
 extern crate iron;
 extern crate mount;
 extern crate logger;
-extern crate rustc_serialize;
+extern crate serde;
 #[macro_use] extern crate juniper;
 
 use std::env;
diff --git a/src/integrations/iron_handlers.rs b/src/integrations/iron_handlers.rs
index 1101aefdd..87f9776a8 100644
--- a/src/integrations/iron_handlers.rs
+++ b/src/integrations/iron_handlers.rs
@@ -1,17 +1,23 @@
 //! Optional handlers for the Iron framework. Requires the `iron-handlers` feature enabled.
-
 use iron::prelude::*;
 use iron::middleware::Handler;
 use iron::mime::Mime;
 use iron::status;
 use iron::method;
-use iron::url::Url;
+use urlencoded::{UrlEncodedQuery, UrlDecodingError};
 
-use std::collections::BTreeMap;
+use std::io::Read;
+use std::io::Error as IoError;
+use std::io::ErrorKind;
+use std::error::Error;
+use std::fmt;
+use std::boxed::Box;
 
-use rustc_serialize::json::{ToJson, Json};
+use serde_json;
+use serde_json::error::Error as SerdeError;
 
-use ::{InputValue, GraphQLType, RootNode, Variables, execute};
+use ::{InputValue, GraphQLType, RootNode, execute};
+use super::serde::{WrappedGraphQLResult, GraphQlQuery};
 
 /// Handler that executes GraphQL queries in the given schema
 ///
@@ -38,6 +44,53 @@ pub struct GraphiQLHandler {
     graphql_url: String,
 }
 
+
+/// Get queries are allowed to repeat the same key more than once.
+fn check_for_repeat_keys(params: &Vec<String>) -> Result<(), IronError> {
+    if params.len() > 1 {
+        let error = IronError::new(
+            Box::new(GraphQlIronError::IO(IoError::new(ErrorKind::InvalidData,
+                                                        "Was able parse a query string \
+                                                        but a duplicate uri key was \
+                                                        found."))),
+                    (status::BadRequest, "Duplicate uri key was found."));
+        Err(error)
+    }
+    else {
+        Ok(())
+    }
+}
+
+fn parse_url_param(param: Option<Vec<String>>) -> Result<Option<String>, IronError> {
+    if let Some(values) = param {
+            check_for_repeat_keys(&values)?;
+            Ok(Some(values[0].to_owned()))
+    }
+    else {
+        Ok(None)
+    }
+}
+
+fn parse_variable_param(param: Option<Vec<String>>) -> Result<Option<InputValue>, IronError> {
+    if let Some(values) = param {
+        check_for_repeat_keys(&values)?;
+        match serde_json::from_str::<InputValue>(values[0].as_ref()) {
+            Ok(input_values) => {
+                Ok(Some(input_values))
+            }
+            Err(err) => {
+                Err(IronError::new(
+                    Box::new(GraphQlIronError::Serde(err)),
+                    (status::BadRequest, "No JSON object was decoded.")))
+            }
+        }
+    }
+    else {
+        Ok(None)
+    }
+}
+
+
 impl<'a, CtxFactory, Query, Mutation, CtxT>
     GraphQLHandler<'a, CtxFactory, Query, Mutation, CtxT>
     where CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
@@ -59,81 +112,62 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
     }
 
 
-    fn handle_get(&self, req: &mut Request) -> IronResult<Response> {
-        let url: Url = req.url.clone().into();
-
-        let mut query = None;
-        let variables = Variables::new();
-
-        for (k, v) in url.query_pairs() {
-            if k == "query" {
-                query = Some(v.into_owned());
-            }
-        }
-
-        let query = iexpect!(query);
-
-        self.execute(req, &query, &variables)
-    }
-
-    fn handle_post(&self, req: &mut Request) -> IronResult<Response> {
-        let json_data = itry!(Json::from_reader(&mut req.body));
-
-        let json_obj = match json_data {
-            Json::Object(o) => o,
-            _ => return Ok(Response::with((status::BadRequest, "No JSON object was decoded"))),
-        };
-
-        let mut query = None;
-        let mut variables = Variables::new();
-
-        for (k, v) in json_obj {
-            if k == "query" {
-                query = v.as_string().map(|s| s.to_owned());
-            }
-            else if k == "variables" {
-                variables = InputValue::from_json(v).to_object_value()
-                    .map(|o| o.into_iter().map(|(k, v)| (k.to_owned(), v.clone())).collect())
-                    .unwrap_or_default();
-            }
-        }
-
-        let query = iexpect!(query);
-
-        self.execute(req, &query, &variables)
-    }
-
-    fn execute(&self, req: &mut Request, query: &str, variables: &Variables) -> IronResult<Response> {
-        let context = (self.context_factory)(req);
-        let result = execute(query, None, &self.root_node, variables, &context);
-
-        let content_type = "application/json".parse::<Mime>().unwrap();
-        let mut map = BTreeMap::new();
-
-        match result {
-            Ok((result, errors)) => {
-                map.insert("data".to_owned(), result.to_json());
-
-                if !errors.is_empty() {
-                    map.insert("errors".to_owned(), errors.to_json());
+    fn handle_get(&self, req: &mut Request) -> IronResult<GraphQlQuery> {
+         match req.get_mut::<UrlEncodedQuery>() {
+            Ok(ref mut query_string) => {
+                let input_query = parse_url_param(query_string.remove("query").to_owned())?;
+                if let Some(query) = input_query {
+                    let operation_name =
+                        parse_url_param(query_string.remove("operationName"))?;
+                    let input_variables =
+                        parse_variable_param(query_string.remove("variables"))?;
+                        Ok(GraphQlQuery::new(query,operation_name,input_variables))
+                } else {
+                    Err(IronError::new(
+                        Box::new(GraphQlIronError::IO(IoError::new(ErrorKind::InvalidData,
+                                                                    "No query key was found in \
+                                                                    the Get request."))),
+                                (status::BadRequest, "No query was provided.")))
                 }
-
-                let data = Json::Object(map);
-                let json = data.pretty();
-
-                Ok(Response::with((content_type, status::Ok, json.to_string())))
             }
-
             Err(err) => {
-                map.insert("errors".to_owned(), err.to_json());
-
-                let data = Json::Object(map);
-                let json = data.pretty();
-
-                Ok(Response::with((content_type, status::BadRequest, json.to_string())))
+                Err(IronError::new(
+                    Box::new(GraphQlIronError::Url(err)),
+                            (status::BadRequest, "No JSON object was decoded.")))
             }
         }
     }
+
+    fn handle_post(&self, req: &mut Request) -> IronResult<GraphQlQuery> {
+        let mut request_payload = String::new();
+        itry!(req.body.read_to_string(&mut request_payload));
+        let graphql_query = serde_json::from_str::<GraphQlQuery>(request_payload.as_str()).map_err(|err|{
+            IronError::new(
+                Box::new(GraphQlIronError::Serde(err)),
+                (status::BadRequest, "No JSON object was decoded."))
+        });
+        graphql_query
+    }
+
+    fn respond(&self, req: &mut Request, graphql: GraphQlQuery) -> IronResult<Response> {
+       let context = (self.context_factory)(req);
+       let variables = graphql.variables();
+       let result = execute(graphql.query(),
+                            graphql.operation_name(),
+                            &self.root_node,
+                            &variables,
+                            &context);
+      let content_type = "application/json".parse::<Mime>().unwrap();
+      if result.is_ok() {
+          let response = WrappedGraphQLResult::new(result);
+          let json = serde_json::to_string_pretty(&response).unwrap();
+          Ok(Response::with((content_type, status::Ok, json)))
+      } else {
+          let response = WrappedGraphQLResult::new(result);
+          let json = serde_json::to_string_pretty(&response).unwrap();
+          Ok(Response::with((content_type, status::BadRequest, json)))
+      }
+   }
 }
 
 impl GraphiQLHandler {
@@ -156,10 +190,16 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
           Query: GraphQLType<Context=CtxT> + Send + Sync + 'static,
           Mutation: GraphQLType<Context=CtxT> + Send + Sync + 'static, 'a: 'static,
 {
-    fn handle(&self, req: &mut Request) -> IronResult<Response> {
+    fn handle(&self, mut req: &mut Request) -> IronResult<Response> {
         match req.method {
-            method::Get => self.handle_get(req),
-            method::Post => self.handle_post(req),
+            method::Get =>  {
+                let graphql_query = self.handle_get(&mut req)?;
+                self.respond(&mut req, graphql_query)
+            }
+            method::Post => {
+                let graphql_query = self.handle_post(&mut req)?;
+                self.respond(&mut req, graphql_query)
+            },
             _ => Ok(Response::with((status::MethodNotAllowed)))
         }
     }
@@ -179,7 +219,6 @@ impl Handler for GraphiQLHandler {
             }
         </style>
         "#;
-
         let fetcher_source = r#"
         <script>
             function graphQLFetcher(params) {
@@ -236,11 +275,62 @@ impl Handler for GraphiQLHandler {
     }
 }
 
+/// A general error allowing the developer to see the underlying issue.
+#[derive(Debug)]
+pub enum GraphQlIronError {
+    ///Captures any errors that were caused by Serde.
+    Serde(SerdeError),
+    /// Captures any error related the IO.
+    IO(IoError),
+    /// Captures any error related to Url Decoding,
+    Url(UrlDecodingError)
+}
+
+impl fmt::Display for GraphQlIronError {
+    fn fmt(&self, mut f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            GraphQlIronError::Serde(ref err) => fmt::Display::fmt(err, &mut f),
+            GraphQlIronError::IO(ref err) => fmt::Display::fmt(err, &mut f),
+            GraphQlIronError::Url(ref err) => fmt::Display::fmt(err, &mut f),
+        }
+    }
+}
+
+impl Error for GraphQlIronError {
+    fn description(&self) -> &str {
+       match *self {
+           GraphQlIronError::Serde(ref err) => {
+               err.description()
+           },
+           GraphQlIronError::IO(ref err) => {
+               err.description()
+           }
+           GraphQlIronError::Url(ref err) => {
+               err.description()
+           }
+       }
+   }
+
+   fn cause(&self) -> Option<&Error> {
+       match *self {
+           GraphQlIronError::Serde(ref err) => {
+               err.cause()
+           }
+           GraphQlIronError::IO(ref err) => {
+               err.cause()
+           }
+           GraphQlIronError::Url(ref err) => {
+               err.cause()
+           }
+       }
+   }
+}
+
 
 #[cfg(test)]
 mod tests {
-    use rustc_serialize::json::Json;
-
+    use serde_json::Value as Json;
+    use serde_json;
     use iron::prelude::*;
     use iron::status;
     use iron::headers;
@@ -267,7 +357,7 @@ mod tests {
     fn unwrap_json_response(resp: Response) -> Json {
         let result = response::extract_body_to_string(resp);
 
-        Json::from_str(&result).expect("Could not parse JSON object")
+        serde_json::from_str::<Json>(&result).expect("Could not parse JSON object")
     }
 
     #[test]
@@ -286,10 +376,77 @@ mod tests {
 
         assert_eq!(
             json,
-            Json::from_str(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
+            serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
                 .expect("Invalid JSON constant in test"));
     }
 
+    #[test]
+    fn test_encoded_get() {
+        let response = request::get(
+            "http://localhost:3000/?query=query%20{%20%20%20human(id:%20\"1000\")%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}",
+            Headers::new(),
+            &make_handler())
+            .expect("Unexpected IronError");
+
+        assert_eq!(response.status, Some(status::Ok));
+        assert_eq!(response.headers.get::<headers::ContentType>(),
+                   Some(&headers::ContentType::json()));
+
+        let json = unwrap_json_response(response);
+
+        assert_eq!(
+            json,
+            serde_json::from_str::<Json>(r#"{
+                    "data": {
+                        "human": {
+                            "appearsIn": [
+                                "NEW_HOPE",
+                                "EMPIRE",
+                                "JEDI"
+                                ],
+                                "homePlanet": "Tatooine",
+                                "name": "Luke Skywalker",
+                                "id": "1000"
+                            }
+                        }
+                    }"#)
+                .expect("Invalid JSON constant in test"));
+    }
+
+    #[test]
+    fn test_get_with_variables() {
+        let response = request::get(
+            "http://localhost:3000/?query=query($id:%20String!)%20{%20%20%20human(id:%20$id)%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}&variables={%20%20%20\"id\":%20%20\"1000\"%20}",
+            Headers::new(),
+            &make_handler())
+            .expect("Unexpected IronError");
+
+        assert_eq!(response.status, Some(status::Ok));
+        assert_eq!(response.headers.get::<headers::ContentType>(),
+                   Some(&headers::ContentType::json()));
+
+        let json = unwrap_json_response(response);
+
+        assert_eq!(
+            json,
+            serde_json::from_str::<Json>(r#"{
+                    "data": {
+                        "human": {
+                            "appearsIn": [
+                                "NEW_HOPE",
+                                "EMPIRE",
+                                "JEDI"
+                                ],
+                                "homePlanet": "Tatooine",
+                                "name": "Luke Skywalker",
+                                "id": "1000"
+                            }
+                        }
+                    }"#)
+                .expect("Invalid JSON constant in test"));
+    }
+
+
     #[test]
     fn test_simple_post() {
         let response = request::post(
@@ -307,7 +464,7 @@ mod tests {
 
         assert_eq!(
             json,
-            Json::from_str(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
+            serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
                 .expect("Invalid JSON constant in test"));
     }
 
diff --git a/src/integrations/mod.rs b/src/integrations/mod.rs
index f597709df..02768f185 100644
--- a/src/integrations/mod.rs
+++ b/src/integrations/mod.rs
@@ -1,3 +1,2 @@
 #[cfg(feature="iron-handlers")] pub mod iron_handlers;
-#[cfg(feature="rustc-serialize")] pub mod rustc_serialize;
-#[cfg(feature="serde")] pub mod serde;
+pub mod serde;
diff --git a/src/integrations/rustc_serialize.rs b/src/integrations/rustc_serialize.rs
deleted file mode 100644
index 23bfdcc81..000000000
--- a/src/integrations/rustc_serialize.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-use rustc_serialize::json::{ToJson, Json};
-
-use ::{GraphQLError, Value};
-use ast::InputValue;
-use executor::ExecutionError;
-use parser::{ParseError, Spanning, SourcePosition};
-use validation::RuleError;
-
-fn parse_error_to_json(err: &Spanning<ParseError>) -> Json {
-    Json::Array(vec![
-        Json::Object(vec![
-            ("message".to_owned(), format!("{}", err.item).to_json()),
-            ("locations".to_owned(), vec![
-                Json::Object(vec![
-                    ("line".to_owned(), (err.start.line() + 1).to_json()),
-                    ("column".to_owned(), (err.start.column() + 1).to_json())
-                ].into_iter().collect()),
-            ].to_json()),
-        ].into_iter().collect()),
-    ])
-}
-
-impl ToJson for ExecutionError {
-    fn to_json(&self) -> Json {
-        Json::Object(vec![
-            ("message".to_owned(), self.message().to_json()),
-            ("locations".to_owned(), vec![self.location().clone()].to_json()),
-            ("path".to_owned(), self.path().to_json()),
-        ].into_iter().collect())
-    }
-}
-
-impl<'a> ToJson for GraphQLError<'a> {
-    fn to_json(&self) -> Json {
-        match *self {
-            GraphQLError::ParseError(ref err) => parse_error_to_json(err),
-            GraphQLError::ValidationError(ref errs) => errs.to_json(),
-            GraphQLError::MultipleOperationsProvided => Json::String(
-                "Must provide operation name if query contains multiple operations".to_owned()),
-            GraphQLError::NoOperationProvided => Json::String(
-                "Must provide an operation".to_owned()),
-            GraphQLError::UnknownOperationName => Json::String(
-                "Unknown operation".to_owned()),
-        }
-    }
-}
-
-impl ToJson for InputValue {
-    fn to_json(&self) -> Json {
-        match *self {
-            InputValue::Null | InputValue::Variable(_) => Json::Null,
-            InputValue::Int(i) => Json::I64(i),
-            InputValue::Float(f) => Json::F64(f),
-            InputValue::String(ref s) | InputValue::Enum(ref s) => Json::String(s.clone()),
-            InputValue::Boolean(b) => Json::Boolean(b),
-            InputValue::List(ref l) => Json::Array(l.iter().map(|x| x.item.to_json()).collect()),
-            InputValue::Object(ref o) => Json::Object(o.iter().map(|&(ref k, ref v)| (k.item.clone(), v.item.to_json())).collect()),
-       }
-    }
-}
-
-impl InputValue {
-    /// Convert a `Json` structure into an `InputValue`.
-    ///
-    /// This consumes the JSON instance.
-    ///
-    /// Notes:
-    /// * No enums or variables will be produced by this method.
-    /// * All lists and objects will be unlocated
-    pub fn from_json(json: Json) -> InputValue {
-        match json {
-            Json::I64(i) => InputValue::int(i),
-            Json::U64(u) => InputValue::float(u as f64),
-            Json::F64(f) => InputValue::float(f),
-            Json::String(s) => InputValue::string(s),
-            Json::Boolean(b) => InputValue::boolean(b),
-            Json::Array(a) => InputValue::list(a.into_iter().map(InputValue::from_json).collect()),
-            Json::Object(o) => InputValue::object(o.into_iter().map(|(k, v)| (k, InputValue::from_json(v))).collect()),
-            Json::Null => InputValue::null(),
-        }
-    }
-}
-
-impl ToJson for RuleError {
-    fn to_json(&self) -> Json {
-        Json::Object(vec![
-            ("message".to_owned(), self.message().to_json()),
-            ("locations".to_owned(), self.locations().to_json()),
-        ].into_iter().collect())
-    }
-}
-
-impl ToJson for SourcePosition {
-    fn to_json(&self) -> Json {
-        Json::Object(vec![
-            ("line".to_owned(), (self.line() + 1).to_json()),
-            ("column".to_owned(), (self.column() + 1).to_json()),
-        ].into_iter().collect())
-    }
-}
-
-impl ToJson for Value {
-    fn to_json(&self) -> Json {
-        match *self {
-            Value::Null => Json::Null,
-            Value::Int(i) => Json::I64(i),
-            Value::Float(f) => Json::F64(f),
-            Value::String(ref s) => Json::String(s.clone()),
-            Value::Boolean(b) => Json::Boolean(b),
-            Value::List(ref l) => Json::Array(l.iter().map(|x| x.to_json()).collect()),
-            Value::Object(ref o) => Json::Object(o.iter().map(|(k,v)| (k.clone(), v.to_json())).collect()),
-       }
-    }
-}
diff --git a/src/integrations/serde.rs b/src/integrations/serde.rs
index e8662949b..3595b9b5c 100644
--- a/src/integrations/serde.rs
+++ b/src/integrations/serde.rs
@@ -1,14 +1,17 @@
 use serde::{de, ser};
 use serde::ser::SerializeMap;
-use std::collections::HashMap;
 use std::fmt;
+use std::collections::HashMap;
 
 use ::{GraphQLError, Value};
+#[cfg(feature="iron-handlers")]
+use ::Variables;
 use ast::InputValue;
 use executor::ExecutionError;
 use parser::{ParseError, Spanning, SourcePosition};
 use validation::RuleError;
 
+
 impl ser::Serialize for ExecutionError {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
         where S: ser::Serializer,
@@ -213,3 +216,87 @@ impl ser::Serialize for Value {
         }
     }
 }
+
+/// The expected structure of the decoded JSON Document for either Post or Get requests.
+#[cfg(feature="iron-handlers")]
+#[derive(Deserialize)]
+pub struct GraphQlQuery {
+    query: String,
+    #[serde(rename = "operationName")]
+    operation_name: Option<String>,
+    variables: Option<InputValue>
+}
+
+#[cfg(feature="iron-handlers")]
+impl GraphQlQuery {
+
+    pub fn new(query: String,
+               operation_name: Option<String>,
+               variables: Option<InputValue>
+              ) ->  GraphQlQuery {
+                GraphQlQuery {
+                    query: query,
+                    operation_name: operation_name,
+                    variables: variables
+                }
+           }
+
+    pub fn query(&self) -> &str {
+        self.query.as_str()
+    }
+
+    pub fn operation_name(&self) -> Option<&str> {
+        self.operation_name.as_ref().map(|oper_name| &**oper_name)
+    }
+
+    pub fn variables(&self) -> Variables {
+        self.variables.as_ref().and_then(|iv| {
+          iv.to_object_value().map(|o| {
+              o.into_iter().map(|(k, v)| (k.to_owned(), v.clone())).collect()
+          })
+      }).unwrap_or_default()
+    }
+
+}
+
+
+#[cfg(feature="iron-handlers")]
+pub struct WrappedGraphQLResult<'a>(Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>);
+
+#[cfg(feature="iron-handlers")]
+impl<'a> WrappedGraphQLResult<'a> {
+    pub fn new(result: Result<(Value, Vec<ExecutionError>),
+               GraphQLError<'a>>
+           ) -> WrappedGraphQLResult<'a> {
+        WrappedGraphQLResult(result)
+    }
+}
+
+#[cfg(feature="iron-handlers")]
+impl<'a> ser::Serialize for WrappedGraphQLResult<'a> {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
+        match self.0 {
+            Ok((ref res, ref err)) => {
+                let mut map = try!(serializer.serialize_map(None));
+
+                try!(map.serialize_key("data"));
+                try!(map.serialize_value(res));
+
+                if !err.is_empty() {
+                    try!(map.serialize_key("errors"));
+                    try!(map.serialize_value(err));
+                }
+
+                map.end()
+            },
+            Err(ref err) => {
+                let mut map = try!(serializer.serialize_map(Some(1)));
+                try!(map.serialize_key("errors"));
+                try!(map.serialize_value(err));
+                map.end()
+            },
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index fb94eaace..0e0bc631f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,7 +14,7 @@ schema, as well as an optional integration into the [Iron framework][2]. It
 tries to keep the number of dynamic operations to a minimum, and give you as the
 schema developer the control of the query execution path.
 
-Juniper only depends on `rustc-serialize` by default, making it lightweight and
+Juniper only depends on `serde` and `serde_json` by default, making it lightweight and
 easy to drop into any project. Through the `iron-handlers` feature, it also
 depends on Iron.
 
@@ -185,13 +185,13 @@ built-in [GraphiQL][6] handler included.
 
 #![cfg_attr(feature="nightly", feature(test))]
 #![warn(missing_docs)]
-
-#[cfg(feature="rustc-serialize")] extern crate rustc_serialize;
-#[cfg(feature="serde")] extern crate serde;
-
 #[cfg(feature="nightly")] extern crate test;
-#[cfg(feature="iron-handlers")] #[macro_use(itry, iexpect)] extern crate iron;
+#[cfg(feature="iron-handlers")] #[macro_use(itry)] extern crate iron;
+#[cfg(feature="iron-handlers")] extern crate urlencoded;
 #[cfg(test)] extern crate iron_test;
+extern crate serde;
+extern crate serde_json;
+#[cfg(feature="iron-handlers")] #[macro_use] extern crate serde_derive;
 
 #[macro_use] mod macros;
 mod ast;


Test patch: