diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml
index 0176fcd4..be2a1dd0 100644
--- a/juniper/Cargo.toml
+++ b/juniper/Cargo.toml
@@ -37,7 +37,7 @@ juniper_codegen = { version = "0.9.2", path = "../juniper_codegen"  }
 fnv = "1.0.3"
 indexmap = { version = "1.0.0", features = ["serde-1"] }
 serde = { version = "1.0.8" }
-serde_derive = {version="1.0.2" }
+serde_derive = { version = "1.0.2" }
 
 chrono = { version = "0.4.0", optional = true }
 serde_json = { version="1.0.2", optional = true }
diff --git a/juniper/src/http/mod.rs b/juniper/src/http/mod.rs
index 96121537..6a32dfa6 100644
--- a/juniper/src/http/mod.rs
+++ b/juniper/src/http/mod.rs
@@ -165,6 +165,9 @@ pub mod tests {
 
         println!("  - test_simple_post");
         test_simple_post(integration);
+
+        println!("  - test_batched_post");
+        test_batched_post(integration);
     }
 
     fn unwrap_json_response(response: &TestResponse) -> Json {
@@ -257,4 +260,17 @@ pub mod tests {
                 .expect("Invalid JSON constant in test")
         );
     }
+
+    fn test_batched_post<T: HTTPIntegration>(integration: &T) {
+        let response = integration.post("/", r#"[{"query": "{hero{name}}"}, {"query": "{hero{name}}"}]"#);
+
+        assert_eq!(response.status_code, 200);
+        assert_eq!(response.content_type, "application/json");
+
+        assert_eq!(
+            unwrap_json_response(&response),
+            serde_json::from_str::<Json>(r#"[{"data": {"hero": {"name": "R2-D2"}}}, {"data": {"hero": {"name": "R2-D2"}}}]"#)
+                .expect("Invalid JSON constant in test")
+        );
+    }
 }
diff --git a/juniper_iron/Cargo.toml b/juniper_iron/Cargo.toml
index 440df4f2..df540d5d 100644
--- a/juniper_iron/Cargo.toml
+++ b/juniper_iron/Cargo.toml
@@ -13,6 +13,7 @@ repository = "https://github.com/graphql-rust/juniper"
 [dependencies]
 serde = { version = "1.0.2" }
 serde_json = { version = "1.0.2" }
+serde_derive = { version = "1.0.2" }
 juniper = { version = "0.9.2", path = "../juniper" }
 
 urlencoded = { version = ">= 0.5, < 0.7" }
diff --git a/juniper_iron/src/lib.rs b/juniper_iron/src/lib.rs
index 58395e2e..24cf86ef 100644
--- a/juniper_iron/src/lib.rs
+++ b/juniper_iron/src/lib.rs
@@ -107,6 +107,8 @@ extern crate iron;
 extern crate iron_test;
 extern crate juniper;
 extern crate serde_json;
+#[macro_use]
+extern crate serde_derive;
 extern crate urlencoded;
 
 use iron::prelude::*;
@@ -125,6 +127,48 @@ use serde_json::error::Error as SerdeError;
 use juniper::{GraphQLType, InputValue, RootNode};
 use juniper::http;
 
+#[derive(Deserialize)]
+#[serde(untagged)]
+enum GraphQLBatchRequest {
+    Single(http::GraphQLRequest),
+    Batch(Vec<http::GraphQLRequest>),
+}
+
+#[derive(Serialize)]
+#[serde(untagged)]
+enum GraphQLBatchResponse<'a> {
+    Single(http::GraphQLResponse<'a>),
+    Batch(Vec<http::GraphQLResponse<'a>>),
+}
+
+impl GraphQLBatchRequest {
+    pub fn execute<'a, CtxT, QueryT, MutationT>(
+        &'a self,
+        root_node: &RootNode<QueryT, MutationT>,
+        context: &CtxT,
+    ) -> GraphQLBatchResponse<'a>
+    where
+        QueryT: GraphQLType<Context = CtxT>,
+        MutationT: GraphQLType<Context = CtxT>,
+    {
+        match self {
+            &GraphQLBatchRequest::Single(ref request) =>
+                GraphQLBatchResponse::Single(request.execute(root_node, context)),
+            &GraphQLBatchRequest::Batch(ref requests) =>
+                GraphQLBatchResponse::Batch(requests.iter().map(|request| request.execute(root_node, context)).collect()),
+        }
+    }
+}
+
+impl<'a> GraphQLBatchResponse<'a> {
+    fn is_ok(&self) -> bool {
+        match self {
+            &GraphQLBatchResponse::Single(ref response) => response.is_ok(),
+            &GraphQLBatchResponse::Batch(ref responses) => responses.iter().fold(true, |ok, response| ok && response.is_ok()),
+        }
+    }
+}
+
 /// Handler that executes `GraphQL` queries in the given schema
 ///
 /// The handler responds to GET requests and POST requests only. In GET
@@ -199,7 +243,7 @@ where
         }
     }
 
-    fn handle_get(&self, req: &mut Request) -> IronResult<http::GraphQLRequest> {
+    fn handle_get(&self, req: &mut Request) -> IronResult<GraphQLBatchRequest> {
         let url_query_string = req.get_mut::<UrlEncodedQuery>()
             .map_err(GraphQLIronError::Url)?;
 
@@ -208,24 +252,24 @@ where
         let operation_name = parse_url_param(url_query_string.remove("operationName"))?;
         let variables = parse_variable_param(url_query_string.remove("variables"))?;
 
-        Ok(http::GraphQLRequest::new(
+        Ok(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
             input_query,
             operation_name,
             variables,
-        ))
+        )))
     }
 
-    fn handle_post(&self, req: &mut Request) -> IronResult<http::GraphQLRequest> {
+    fn handle_post(&self, req: &mut Request) -> IronResult<GraphQLBatchRequest> {
         let mut request_payload = String::new();
         itry!(req.body.read_to_string(&mut request_payload));
 
         Ok(
-            serde_json::from_str::<http::GraphQLRequest>(request_payload.as_str())
+            serde_json::from_str::<GraphQLBatchRequest>(request_payload.as_str())
                 .map_err(GraphQLIronError::Serde)?,
         )
     }
 
-    fn execute(&self, context: &CtxT, request: http::GraphQLRequest) -> IronResult<Response> {
+    fn execute(&self, context: &CtxT, request: GraphQLBatchRequest) -> IronResult<Response> {
         let response = request.execute(&self.root_node, context);
         let content_type = "application/json".parse::<Mime>().unwrap();
         let json = serde_json::to_string_pretty(&response).unwrap();
diff --git a/juniper_rocket/Cargo.toml b/juniper_rocket/Cargo.toml
index bc123b04..547e487b 100644
--- a/juniper_rocket/Cargo.toml
+++ b/juniper_rocket/Cargo.toml
@@ -12,8 +12,8 @@ repository = "https://github.com/graphql-rust/juniper"
 
 [dependencies]
 serde = { version = "1.0.2" }
-serde_derive = {version="1.0.2" }
 serde_json = { version = "1.0.2" }
+serde_derive = { version = "1.0.2" }
 juniper = { version = "0.9.2" , path = "../juniper"}
 
 rocket = { version = "0.3.9" }
diff --git a/juniper_rocket/src/lib.rs b/juniper_rocket/src/lib.rs
index 70a82390..a204d212 100644
--- a/juniper_rocket/src/lib.rs
+++ b/juniper_rocket/src/lib.rs
@@ -42,6 +42,8 @@ Check the LICENSE file for details.
 extern crate juniper;
 extern crate rocket;
 extern crate serde_json;
+#[macro_use]
+extern crate serde_derive;
 
 use std::io::{Cursor, Read};
 use std::error::Error;
@@ -61,13 +63,55 @@ use juniper::GraphQLType;
 use juniper::FieldError;
 use juniper::RootNode;
 
+#[derive(Debug, Deserialize, PartialEq)]
+#[serde(untagged)]
+enum GraphQLBatchRequest {
+    Single(http::GraphQLRequest),
+    Batch(Vec<http::GraphQLRequest>),
+}
+
+#[derive(Serialize)]
+#[serde(untagged)]
+enum GraphQLBatchResponse<'a> {
+    Single(http::GraphQLResponse<'a>),
+    Batch(Vec<http::GraphQLResponse<'a>>),
+}
+
+impl GraphQLBatchRequest {
+    pub fn execute<'a, CtxT, QueryT, MutationT>(
+        &'a self,
+        root_node: &RootNode<QueryT, MutationT>,
+        context: &CtxT,
+    ) -> GraphQLBatchResponse<'a>
+    where
+        QueryT: GraphQLType<Context = CtxT>,
+        MutationT: GraphQLType<Context = CtxT>,
+    {
+        match self {
+            &GraphQLBatchRequest::Single(ref request) =>
+                GraphQLBatchResponse::Single(request.execute(root_node, context)),
+            &GraphQLBatchRequest::Batch(ref requests) =>
+                GraphQLBatchResponse::Batch(requests.iter().map(|request| request.execute(root_node, context)).collect()),
+        }
+    }
+}
+
+impl<'a> GraphQLBatchResponse<'a> {
+    fn is_ok(&self) -> bool {
+        match self {
+            &GraphQLBatchResponse::Single(ref response) => response.is_ok(),
+            &GraphQLBatchResponse::Batch(ref responses) => responses.iter().fold(true, |ok, response| ok && response.is_ok()),
+        }
+    }
+}
+
 /// Simple wrapper around an incoming GraphQL request
 ///
 /// See the `http` module for more information. This type can be constructed
 /// automatically from both GET and POST routes by implementing the `FromForm`
 /// and `FromData` traits.
 #[derive(Debug, PartialEq)]
-pub struct GraphQLRequest(http::GraphQLRequest);
+pub struct GraphQLRequest(GraphQLBatchRequest);
 
 /// Simple wrapper around the result of executing a GraphQL query
 pub struct GraphQLResponse(Status, String);
@@ -209,11 +253,11 @@ impl<'f> FromForm<'f> for GraphQLRequest {
         }
 
         if let Some(query) = query {
-            Ok(GraphQLRequest(http::GraphQLRequest::new(
+            Ok(GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
                 query,
                 operation_name,
                 variables,
-            )))
+            ))))
         } else {
             Err("Query parameter missing".to_owned())
         }
@@ -324,11 +368,11 @@ mod fromform_tests {
         let result = GraphQLRequest::from_form(&mut items, false);
         assert!(result.is_ok());
         let variables = ::serde_json::from_str::<InputValue>(r#"{"foo":"bar"}"#).unwrap();
-        let expected = GraphQLRequest(http::GraphQLRequest::new(
+        let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
             "test".to_string(),
             None,
             Some(variables),
-        ));
+        )));
         assert_eq!(result.unwrap(), expected);
     }
 
@@ -339,11 +383,11 @@ mod fromform_tests {
         let result = GraphQLRequest::from_form(&mut items, false);
         assert!(result.is_ok());
         let variables = ::serde_json::from_str::<InputValue>(r#"{"foo":"x y&? z"}"#).unwrap();
-        let expected = GraphQLRequest(http::GraphQLRequest::new(
+        let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
             "test".to_string(),
             None,
             Some(variables),
-        ));
+        )));
         assert_eq!(result.unwrap(), expected);
     }
 
@@ -353,11 +397,11 @@ mod fromform_tests {
         let mut items = FormItems::from(form_string);
         let result = GraphQLRequest::from_form(&mut items, false);
         assert!(result.is_ok());
-        let expected = GraphQLRequest(http::GraphQLRequest::new(
+        let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
             "%foo bar baz&?".to_string(),
             Some("test".to_string()),
             None,
-        ));
+        )));
         assert_eq!(result.unwrap(), expected);
     }
 }