diff --git a/.gitignore b/.gitignore
index 49d56a8..ede0f43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 _book
 _skeptic/target
 node_modules
+*.swp
diff --git a/.travis.yml b/.travis.yml
index 11ed16e..6f6724b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,19 +1,26 @@
-language: node_js
-node_js:
-  - "8"
+language: rust
+rust:
+  - stable
+  - beta
+  - nightly
 
 env:
   global:
     - secure: "vaPicq7s2hHBZwtG5eZ1wSmlIYog8FBZ7OilJs6cXQ0fyP5FqGFdc+VG+FSNbEDqPct/v5ojrfbwhQWZVjzgyMZ+Ikrpd9QD0T2Ie4f5yHh2schpphiog7pAfRG1A56/JsGq7aZr76DsICYUGeU4d8BzjaeFC2ozoo5tE9NXpp5ENLFNuErYGwMcQ0vlLTrK2miyuDn18HasHeT5pmxZT1qN5KjxzqChTvEFbH9pQsVKv+dVQiWVifYt4beOfSxaZJmCyBJHv2MjUOyWmYPtqikVxz4dkTbS/Cyx9dK3u2AgrH2Trrl0RFa5VKQUA+06v9NC+oH8NJj72aw44JdryVTchfQw3VF27H/2xfeg3WJX87/1J1oWvCBBtFWU5UwWapXq4Tz7UjT75H7unmlnc11hwmgMklpqMpD52om8n/GLMY2wkS5/dPJpLbYWt6OnBCPtHdP2EO59Wxg1YJ73PZdsrC81z3t8c4SSUXCmzUCG7P8UrSjpBl0g3yXTtR1/fvvSU1qQLFIDN8ib4tl8KGEgbX1ipJkkgCExriuZ58wOPqOdioqNMfWxyGszqxALsL1qxcET8ZtVOzIRCGuVptV0cUujxUwM9LJBqWq4MqPVO9+98FtX6xZvMM5gUM2dq4gWI45KK/VcNEkgihoSKUyVR2OaW5sTs6d28OejOXs="
 
 before_install:
-  - curl https://sh.rustup.rs -sSf | sh -s -- -y
-  - export PATH=$HOME/.cargo/bin:$PATH
-  - rustup update
+  # Install node.
+  - curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
+  - sudo apt-get install -y nodejs
+  # Install yarn.
+  - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+  - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+  - sudo apt-get update && sudo apt-get install -y yarn
 
 script:
-  # - yarn test
+  - yarn
   - yarn build
+  - yarn test
   - touch _book/.nojekyll
 
 branches:
@@ -26,5 +33,6 @@ deploy:
   github_token: $DEPLOY_TOKEN
   on:
     branch: source
+    rust: stable
   target_branch: master
   local_dir: _book/
diff --git a/README.md b/README.md
index 827c8e8..360b923 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,12 @@
-Work in progress with improved documentation and main website for Juniper.
\ No newline at end of file
+Work in progress with improved documentation and main website for Juniper.
+
+## Requirements
+
+- Node.js
+- `yarn`
+
+## Contributing
+
+- Run `yarn build` to build your changes.
+- Run `yarn serve` to view your changes.
+- Run `yarn test` to test your changes.
diff --git a/_skeptic/Cargo.toml b/_skeptic/Cargo.toml
index 2cbd8da..47b6c13 100644
--- a/_skeptic/Cargo.toml
+++ b/_skeptic/Cargo.toml
@@ -11,12 +11,10 @@ juniper_iron = { git = "https://github.com/graphql-rust/juniper" }
 iron = "^0.5.0"
 mount = "^0.3.0"
 
-skeptic = "0.12"
+skeptic = "0.13"
 
 [build-dependencies]
-skeptic = "0.12"
+skeptic = "0.13"
 
 [patch.crates-io]
 juniper_codegen = { git = "https://github.com/graphql-rust/juniper" }
-
-
diff --git a/book.json b/book.json
index 8e0cfc4..39252e6 100644
--- a/book.json
+++ b/book.json
@@ -1,5 +1,6 @@
 {
     "plugins": [
+        "anchors",
         "codeblock-omit",
         "codeblock-rust",
         "sane-sidebar",
diff --git a/docs/README.md b/docs/README.md
index 319630f..586a066 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -4,27 +4,25 @@ Juniper is a [GraphQL] server library for Rust. Build type-safe and fast API
 servers with minimal boilerplate and configuration.
 
 [GraphQL][graphql] is a data query language developed by Facebook intended to
-serve mobile and web application frontends. 
+serve mobile and web application frontends.
 
-Juniper makes it possible to write GraphQL servers in Rust that are 
-type-safe and blazingly fast. We also try to make declaring and resolving 
+_Juniper_ makes it possible to write GraphQL servers in Rust that are
+type-safe and blazingly fast. We also try to make declaring and resolving
 GraphQL schemas as convenient as possible as Rust will allow.
 
 Juniper does not include a web server - instead it provides building blocks to
 make integration with existing servers straightforward. It optionally provides a
-pre-built integration for the [Iron][iron] and [Rocket] frameworks, including
+pre-built integration for the [Hyper][hyper], [Iron][iron], [Rocket], and [Warp][warp] frameworks, including
 embedded [Graphiql][graphiql] for easy debugging.
 
-* [Github](https://github.com/graphql-rust/juniper)
-* [Cargo crate](https://crates.io/crates/juniper)
-* [API Reference][docsrs]
-
+- [Cargo crate](https://crates.io/crates/juniper)
+- [API Reference][docsrs]
 
 ## Features
 
 Juniper supports the full GraphQL query language according to the
-[specification][graphql_spec], including interfaces, unions, schema 
-introspection, and validations.  
+[specification][graphql_spec], including interfaces, unions, schema
+introspection, and validations.
 It does not, however, support the schema language.
 
 As an exception to other GraphQL libraries for other languages, Juniper builds
@@ -40,15 +38,16 @@ Juniper has automatic integration with some very common Rust crates to make
 building schemas a breeze. The types from these crates will be usable in
 your Schemas automatically.
 
-* [uuid][uuid]
-* [url][url]
-* [chrono][chrono]
+- [uuid][uuid]
+- [url][url]
+- [chrono][chrono]
 
 ### Web Frameworks
 
-* [rocket][rocket]
-* [iron][iron]
-
+- [hyper][hyper]
+- [rocket][rocket]
+- [iron][iron]
+- [warp][warp]
 
 ## API Stability
 
@@ -56,17 +55,20 @@ Juniper has not reached 1.0 yet, thus some API instability should be expected.
 
 [graphql]: http://graphql.org
 [graphiql]: https://github.com/graphql/graphiql
-[iron]: http://ironframework.io
+[iron]: https://github.com/iron/iron
 [graphql_spec]: http://facebook.github.io/graphql
-[test_schema_rs]: https://github.com/graphql-rust/juniper/blob/master/src/tests/schema.rs
+[test_schema_rs]: https://github.com/graphql-rust/juniper/blob/master/juniper/src/tests/schema.rs
 [tokio]: https://github.com/tokio-rs/tokio
+[hyper_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_hyper/examples
 [rocket_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_rocket/examples
 [iron_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_iron/examples
-[Rocket]: https://rocket.rs
-[book]: https://graphql-rust.github.io/juniper-book
-[book_quickstart]: https://graphql-rust.github.io/juniper-book/quickstart.html
+[hyper]: https://hyper.rs
+[rocket]: https://rocket.rs
+[book]: https://graphql-rust.github.io
+[book_quickstart]: https://graphql-rust.github.io/quickstart.html
 [docsrs]: https://docs.rs/juniper
-
+[warp]: https://github.com/seanmonstar/warp
+[warp_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_warp/examples
 [uuid]: https://crates.io/crates/uuid
 [url]: https://crates.io/crates/url
 [chrono]: https://crates.io/crates/chrono
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index d82ee17..0a5a966 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -1,34 +1,41 @@
 # Summary
 
-* [Introduction](README.md)
-* [Quickstart](quickstart.md)
+- [Introduction](README.md)
+- [Quickstart](quickstart.md)
 
 ## Type System
 
-* [Defining objects](types/objects/defining_objects.md)
-    * [Complex fields](types/objects/complex_fields.md)
-    * [Using contexts](types/objects/using_contexts.md)
-    * [Error handling](types/objects/error_handling.md)
-* Other types
-  * [Enums](types/enums.md)
-  * [Interfaces](types/interfaces.md)
-  * [Input objects](types/input_objects.md)
-  * [Scalars](types/scalars.md)
-  * [Unions](types/unions.md)
-
+- [Defining objects](types/objects/defining_objects.md)
+  - [Complex fields](types/objects/complex_fields.md)
+  - [Using contexts](types/objects/using_contexts.md)
+  - [Error handling](types/objects/error_handling.md)
+- Other types
+  - [Enums](types/enums.md)
+  - [Interfaces](types/interfaces.md)
+  - [Input objects](types/input_objects.md)
+  - [Scalars](types/scalars.md)
+  - [Unions](types/unions.md)
 
 ## Schema
 
-* [Schemas and mutations](schema/schemas_and_mutations.md)
+- [Schemas and mutations](schema/schemas_and_mutations.md)
 
 ## Adding a server
 
-* [Rocket](servers/rocket.md)
-* [Iron](servers/iron.md)
+- Integrations by Juniper
+  - [Hyper](servers/hyper.md)
+  - [Warp](servers/warp.md)
+  - [Rocket](servers/rocket.md)
+  - [Iron](servers/iron.md)
+- Integrations by others
+  - [Actix-Web](https://github.com/actix/examples/tree/master/graphql/juniper)
+  - [Finchers](https://github.com/finchers-rs/finchers-juniper)
+  - [Tsukuyomi](https://github.com/tsukuyomi-rs/tsukuyomi/tree/master/examples/juniper)
 
 ## Advanced Topics
 
-* [Non-struct objects](advanced/non_struct_objects.md)
-* [Objects and generics](advanced/objects_and_generics.md)
-* [Context switching]
-* [Dynamic type system]
+- [Non-struct objects](advanced/non_struct_objects.md)
+- [Objects and generics](advanced/objects_and_generics.md)
+- [Context switching]
+- [Dynamic type system]
+- [Multiple operations per request](advanced/multiple_ops_per_request.md)
diff --git a/docs/advanced/multiple_ops_per_request.md b/docs/advanced/multiple_ops_per_request.md
new file mode 100644
index 0000000..27d88c9
--- /dev/null
+++ b/docs/advanced/multiple_ops_per_request.md
@@ -0,0 +1,73 @@
+# Multiple operations per request
+
+The GraphQL standard generally assumes there will be one server request for each client operation you want to perform (such as a query or mutation). This is conceptually simple but has the potential to be inefficent.
+
+Some client libraries such as [apollo-link-batch-http](https://www.apollographql.com/docs/link/links/batch-http.html) have added the ability to batch operations in a single HTTP request to save network round-trips and potentially increase performance. There are some [tradeoffs](https://blog.apollographql.com/batching-client-graphql-queries-a685f5bcd41b) that should be considered before batching requests.
+
+Juniper's server integration crates support multiple operations in a single HTTP request using JSON arrays. This makes them compatible with client libraries that support batch operations without any special configuration.
+
+Server integration crates maintained by others are **not required** to support batch requests. Batch requests aren't part of the official GraphQL specification.
+
+Assuming an integration supports batch requests, for the following GraphQL query:
+
+```graphql
+{
+  hero {
+    name
+  }
+}
+```
+
+The json data to POST to the server for an individual request would be:
+
+```json
+{
+  "query": "{hero{name}}"
+}
+```
+
+And the response would be of the form:
+
+```json
+{
+  "data": {
+    "hero": {
+      "name": "R2-D2"
+    }
+  }
+}
+```
+
+If you wanted to run the same query twice in a single HTTP request, the batched json data to POST to the server would be:
+
+```json
+[
+  {
+    "query": "{hero{name}}"
+  },
+  {
+    "query": "{hero{name}}"
+  }
+]
+```
+
+And the response would be of the form:
+
+```json
+[
+  {
+    "data": {
+      "hero": {
+        "name": "R2-D2"
+      }
+    }
+  },
+  {
+    "data": {
+      "hero": {
+        "name": "R2-D2"
+      }
+    }
+  }
+]
+```
diff --git a/docs/quickstart.md b/docs/quickstart.md
index bdf12d8..52007d9 100644
--- a/docs/quickstart.md
+++ b/docs/quickstart.md
@@ -2,17 +2,17 @@
 
 This page will give you a short introduction to the concepts in Juniper.
 
-Once you are done here, head over to the [Tutorial][tutorial] to learn how to 
+Once you are done here, head over to the [Tutorial][tutorial] to learn how to
 use Juniper by creating a full setup step by step, or consult the other chapters
 for more detailed information.
 
-
 ## Installation
 
 !FILENAME Cargo.toml
+
 ```toml
 [dependencies]
-juniper = "0.9.0"
+juniper = "0.10"
 ```
 
 ## Schema example
@@ -23,26 +23,23 @@ naturally map to GraphQL features, such as `Option<T>`, `Vec<T>`, `Box<T>`,
 `String`, `f64`, and `i32`, references, and slices.
 
 For more advanced mappings, Juniper provides multiple macros to map your Rust
-types to a GraphQL schema. The most important one is the 
+types to a GraphQL schema. The most important one is the
 [graphql_object!][jp_obj_macro] macro that is used for declaring an object with
 resolvers, which you will use for the `Query` and `Mutation` roots.
 
 !FILENAME main.rs
-```rust
 
+```rust
 #[macro_use] extern crate juniper;
 
 use juniper::{FieldResult};
 
-#struct DatabasePool;
-#impl DatabasePool {
-#       fn get_connection(&self) -> FieldResult<DatabasePool> { Ok(DatabasePool) }
-#       fn find_human(&self, id: &str) -> FieldResult<Human> { Err("")? }
-#       fn insert_human(&self, human: &NewHuman) -> FieldResult<Human> { Err("")? }
-#     }
-
-
-use juniper::{FieldResult};
+# struct DatabasePool;
+# impl DatabasePool {
+#     fn get_connection(&self) -> FieldResult<DatabasePool> { Ok(DatabasePool) }
+#     fn find_human(&self, id: &str) -> FieldResult<Human> { Err("")? }
+#     fn insert_human(&self, human: &NewHuman) -> FieldResult<Human> { Err("")? }
+# }
 
 #[derive(GraphQLEnum)]
 enum Episode {
@@ -124,15 +121,71 @@ type Schema = juniper::RootNode<'static, Query, Mutation>;
 fn main() {
     println!("Hello, world!");
 }
-
 ```
 
 We now have a very simple but functional schema for a GraphQL server!
 
-To actually serve the schema, see the guides for our [Rocket][rocket_guide] or 
-[Iron][iron_guide] integrations.
+To actually serve the schema, see the guides for our [Hyper], [Rocket],
+[Warp], and [Iron] server integrations. Or you can invoke the executor directly:
+
+## Executor
+
+You can invoke `juniper::execute` directly to run a GraphQL query:
+
+!FILENAME main.rs
+
+```rust
+#[macro_use] extern crate juniper;
+
+use juniper::{FieldResult, Variables, EmptyMutation};
+
+#[derive(GraphQLEnum, Clone, Copy)]
+enum Episode {
+    NewHope,
+    Empire,
+    Jedi,
+}
+
+struct Query;
+
+graphql_object!(Query: Ctx |&self| {
+    field favoriteEpisode(&executor) -> FieldResult<Episode> {
+        // Use the special &executor argument to fetch our fav episode.
+        Ok(executor.context().0)
+    }
+});
+
+// Arbitrary context data.
+struct Ctx(Episode);
+
+// A root schema consists of a query and a mutation.
+// Request queries can be executed against a RootNode.
+type Schema = juniper::RootNode<'static, Query, EmptyMutation<Ctx>>;
+
+fn main() {
+    // Create a context object.
+    let ctx = Ctx(Episode::NewHope);
+
+    // Run the executor.
+    let (res, _errors) = juniper::execute(
+        "query { favoriteEpisode }",
+        None,
+        &Schema::new(Query, EmptyMutation::new()),
+        &Variables::new(),
+        &ctx,
+    ).unwrap();
+
+    // Ensure the value matches.
+    assert_eq!(
+        res.as_object_value().unwrap().get_field_value("favoriteEpisode").unwrap().as_string_value().unwrap(),
+        "NEW_HOPE",
+    );
+}
+```
 
+[hyper]: servers/hyper.md
+[warp]: servers/warp.md
+[rocket]: servers/rocket.md
+[iron]: servers/iron.md
 [tutorial]: ./tutorial.html
-[jp_obj_macro]: https://docs.rs/juniper/0.9.0/juniper/macro.graphql_object.html
-[rocket_guide]: ./servers/rocket.html
-[iron_guide]: ./servers/iron.html
+[jp_obj_macro]: https://docs.rs/juniper/latest/juniper/attr.graphql_object.html
diff --git a/docs/servers/hyper.md b/docs/servers/hyper.md
new file mode 100644
index 0000000..c3e5686
--- /dev/null
+++ b/docs/servers/hyper.md
@@ -0,0 +1,28 @@
+# Integrating with Hyper
+
+[Hyper] is a fast HTTP implementation that many other Rust web frameworks
+leverage. It offers asynchronous I/O via the tokio runtime and works on
+Rust's stable channel.
+
+Hyper is not a higher-level web framework and accordingly
+does not include ergonomic features such as simple endpoint routing,
+baked-in HTTP responses, or reusable middleware. For GraphQL, those aren't
+large downsides as all POSTs and GETs usually go through a single endpoint with
+a few clearly-defined response payloads.
+
+Juniper's Hyper integration is contained in the [`juniper_hyper`][juniper_hyper] crate:
+
+!FILENAME Cargo.toml
+
+```toml
+[dependencies]
+juniper = "0.10"
+juniper_hyper = "0.1.0"
+```
+
+Included in the source is a [small example][example] which sets up a basic GraphQL and [GraphiQL] handler.
+
+[graphiql]: https://github.com/graphql/graphiql
+[hyper]: https://hyper.rs/
+[juniper_hyper]: https://github.com/graphql-rust/juniper/tree/master/juniper_hyper
+[example]: https://github.com/graphql-rust/juniper/blob/master/juniper_hyper/examples/hyper_server.rs
diff --git a/docs/servers/iron.md b/docs/servers/iron.md
index 665c3d8..f86640f 100644
--- a/docs/servers/iron.md
+++ b/docs/servers/iron.md
@@ -8,10 +8,11 @@ channel.
 Juniper's Iron integration is contained in the `juniper_iron` crate:
 
 !FILENAME Cargo.toml
+
 ```toml
 [dependencies]
-juniper = "0.9.0"
-juniper_iron = "0.1.0"
+juniper = "0.10"
+juniper_iron = "0.2.0"
 ```
 
 Included in the source is a [small
@@ -29,7 +30,7 @@ set up other global data that the schema might require.
 
 In this example, we won't use any global data so we just return an empty value.
 
-```rust
+```rust,ignore
 #[macro_use] extern crate juniper;
 extern crate juniper_iron;
 extern crate iron;
@@ -40,15 +41,15 @@ use iron::prelude::*;
 use juniper::EmptyMutation;
 use juniper_iron::GraphQLHandler;
 
-fn context_factory(_: &mut Request) -> () {
-    ()
+fn context_factory(_: &mut Request) -> IronResult<()> {
+    Ok(())
 }
 
 struct Root;
 
 graphql_object!(Root: () |&self| {
     field foo() -> String {
-        "Bar".to_owned() 
+        "Bar".to_owned()
     }
 });
 
@@ -77,7 +78,7 @@ If you want to access e.g. the source IP address of the request from a field
 resolver, you need to pass this data using Juniper's [context
 feature](context.md).
 
-```rust
+```rust,ignore
 # #[macro_use] extern crate juniper;
 # extern crate juniper_iron;
 # extern crate iron;
@@ -90,10 +91,10 @@ struct Context {
 
 impl juniper::Context for Context {}
 
-fn context_factory(req: &mut Request) -> Context {
-    Context {
+fn context_factory(req: &mut Request) -> IronResult<Context> {
+    Ok(Context {
         remote_addr: req.remote_addr
-    }
+    })
 }
 
 struct Root;
@@ -119,7 +120,6 @@ graphql_object!(Root: Context |&self| {
 
 FIXME: Show how the `persistent` crate works with contexts using e.g. `r2d2`.
 
-
-[Iron]: http://ironframework.io
-[GraphiQL]: https://github.com/graphql/graphiql
+[iron]: https://github.com/iron/iron
+[graphiql]: https://github.com/graphql/graphiql
 [mount]: https://github.com/iron/mount
diff --git a/docs/servers/rocket.md b/docs/servers/rocket.md
index 21e4840..69a152e 100644
--- a/docs/servers/rocket.md
+++ b/docs/servers/rocket.md
@@ -1,3 +1,22 @@
 # Integrating with Rocket
 
-...
+[Rocket] is a web framework for Rust that makes it simple to write fast web applications without sacrificing flexibility or type safety. All with minimal code. Rocket
+does not work on Rust's stable channel and instead requires the nightly
+channel.
+
+Juniper's Rocket integration is contained in the [`juniper_rocket`][juniper_rocket] crate:
+
+!FILENAME Cargo.toml
+
+```toml
+[dependencies]
+juniper = "0.10"
+juniper_rocket = "0.2.0"
+```
+
+Included in the source is a [small example][example] which sets up a basic GraphQL and [GraphiQL] handler.
+
+[graphiql]: https://github.com/graphql/graphiql
+[rocket]: https://rocket.rs/
+[juniper_rocket]: https://github.com/graphql-rust/juniper/tree/master/juniper_rocket
+[example]: https://github.com/graphql-rust/juniper/blob/master/juniper_rocket/examples/rocket_server.rs
diff --git a/docs/servers/warp.md b/docs/servers/warp.md
new file mode 100644
index 0000000..6fa4d86
--- /dev/null
+++ b/docs/servers/warp.md
@@ -0,0 +1,23 @@
+# Integrating with Warp
+
+[Warp] is a super-easy, composable, web server framework for warp speeds.
+The fundamental building block of warp is the Filter: they can be combined and composed to express rich requirements on requests. Warp is built on [Hyper] and works on
+Rust's stable channel.
+
+Juniper's Warp integration is contained in the [`juniper_warp`][juniper_warp] crate:
+
+!FILENAME Cargo.toml
+
+```toml
+[dependencies]
+juniper = "0.10"
+juniper_warp = "0.1.0"
+```
+
+Included in the source is a [small example][example] which sets up a basic GraphQL and [GraphiQL] handler.
+
+[graphiql]: https://github.com/graphql/graphiql
+[hyper]: https://hyper.rs/
+[warp]: https://crates.io/crates/warp
+[juniper_warp]: https://github.com/graphql-rust/juniper/tree/master/juniper_warp
+[example]: https://github.com/graphql-rust/juniper/tree/master/juniper_warp/examples/warp_server.rs
diff --git a/docs/types/interfaces.md b/docs/types/interfaces.md
index c093ba9..56abeee 100644
--- a/docs/types/interfaces.md
+++ b/docs/types/interfaces.md
@@ -13,7 +13,7 @@ let's have a look at the same end-result from a few different implementations:
 
 Traits are maybe the most obvious concept you want to use when building
 interfaces. But because GraphQL supports downcasting while Rust doesn't, you'll
-have to manually specify how to convert an trait into a concrete type. This can
+have to manually specify how to convert a trait into a concrete type. This can
 be done in a couple of different ways:
 
 ### Downcasting via accessor methods
diff --git a/docs/types/objects/defining_objects.md b/docs/types/objects/defining_objects.md
index f71bdef..b5596c6 100644
--- a/docs/types/objects/defining_objects.md
+++ b/docs/types/objects/defining_objects.md
@@ -28,18 +28,41 @@ can use `Option<T>`.
 
 We should take advantage of the
 fact that GraphQL is self-documenting and add descriptions to the type and
-fields:
+fields. Juniper will automatically use associated doc comments as GraphQL
+descriptions:
+
+!FILENAME GraphQL descriptions via Rust doc comments
+
+```rust
+# extern crate juniper;
+# #[macro_use] extern crate juniper_codegen;
+#
+#[derive(GraphQLObject)]
+/// Information about a person
+struct Person {
+    /// The person's full name, including both first and last names
+    name: String,
+    /// The person's age in years, rounded down
+    age: i32,
+}
+
+# fn main() {}
+```
+
+Objects and fields without doc comments can instead set a `description`
+via the `graphql` attribute. The following example is equivalent to the above:
+
+!FILENAME GraphQL descriptions via attribute
 
 ```rust
 # extern crate juniper;
 # #[macro_use] extern crate juniper_codegen;
-# 
+#
 #[derive(GraphQLObject)]
 #[graphql(description="Information about a person")]
 struct Person {
     #[graphql(description="The person's full name, including both first and last names")]
     name: String,
-
     #[graphql(description="The person's age in years, rounded down")]
     age: i32,
 }
@@ -47,16 +70,38 @@ struct Person {
 # fn main() {}
 ```
 
+Descriptions set via the `graphql` attribute take precedence over Rust
+doc comments. This enables internal Rust documentation and external GraphQL
+documentation to differ:
+
+```rust
+# extern crate juniper;
+# #[macro_use] extern crate juniper_codegen;
+#
+#[derive(GraphQLObject)]
+#[graphql(description="This description shows up in GraphQL")]
+/// This description shows up in RustDoc
+struct Person {
+    #[graphql(description="This description shows up in GraphQL")]
+    /// This description shows up in RustDoc
+    name: String,
+    /// This description shows up in both RustDoc and GraphQL
+    age: i32,
+}
+
+# fn main() {}
+```
+
 ## Relationships
 
 You can only use the custom derive attribute under these circumstances:
 
-* The annotated type is a `struct`,
-* Every struct field is either
-  * A primitive type (`i32`, `f64`, `bool`, `String`, `juniper::ID`), or
-  * A valid custom GraphQL type, e.g. another struct marked with this attribute,
+- The annotated type is a `struct`,
+- Every struct field is either
+  - A primitive type (`i32`, `f64`, `bool`, `String`, `juniper::ID`), or
+  - A valid custom GraphQL type, e.g. another struct marked with this attribute,
     or
-  * A container/reference containing any of the above, e.g. `Vec<T>`, `Box<T>`,
+  - A container/reference containing any of the above, e.g. `Vec<T>`, `Box<T>`,
     `Option<T>`
 
 Let's see what that means for building relationships between objects:
@@ -92,7 +137,7 @@ convention into GraphQL's `camelCase` convention:
 ```rust
 # extern crate juniper;
 # #[macro_use] extern crate juniper_codegen;
-# 
+#
 #[derive(GraphQLObject)]
 struct Person {
     first_name: String, // Would be exposed as firstName in the GraphQL schema
@@ -108,7 +153,7 @@ fields:
 ```rust
 # extern crate juniper;
 # #[macro_use] extern crate juniper_codegen;
-# 
+#
 #[derive(GraphQLObject)]
 struct Person {
     name: String,
@@ -128,7 +173,7 @@ attribute:
 ```rust
 # extern crate juniper;
 # #[macro_use] extern crate juniper_codegen;
-# 
+#
 #[derive(GraphQLObject)]
 struct Person {
     name: String,
@@ -141,5 +186,24 @@ struct Person {
 ```
 
 The `name`, `description`, and `deprecation` arguments can of course be
-combined. Some restrictions from the GraphQL spec stil applies though; you can
-only deprecate object fields and enum values.
\ No newline at end of file
+combined. Some restrictions from the GraphQL spec still applies though; you can
+only deprecate object fields and enum values.
+
+## Skipping fields
+
+By default all fields in a `GraphQLObject` are included in the generated GraphQL type. To prevent including a specific field, annotate the field with `#[graphql(skip)]`:
+
+```rust
+# extern crate juniper;
+# #[macro_use] extern crate juniper_codegen;
+#
+#[derive(GraphQLObject)]
+struct Person {
+    name: String,
+    age: i32,
+    #[graphql(skip)]
+    password_hash: String, // This cannot be queried or modified from GraphQL
+}
+
+# fn main() {}
+```
diff --git a/docs/types/objects/error_handling.md b/docs/types/objects/error_handling.md
index 40a63f9..d415b33 100644
--- a/docs/types/objects/error_handling.md
+++ b/docs/types/objects/error_handling.md
@@ -17,6 +17,7 @@ use juniper::FieldResult;
 use std::path::PathBuf;
 use std::fs::File;
 use std::io::Read;
+use std::str;
 
 struct Example {
     filename: PathBuf,
@@ -29,6 +30,15 @@ graphql_object!(Example: () |&self| {
         file.read_to_string(&mut contents)?;
         Ok(contents)
     }
+    field foo() -> FieldResult<Option<String>> {
+      // Some invalid bytes.
+      let invalid = vec![128, 223];
+
+      match str::from_utf8(&invalid) {
+        Ok(s) => Ok(Some(s.to_string())),
+        Err(e) => Err(e)?,
+      }
+    }
 });
 
 # fn main() {}
@@ -41,6 +51,118 @@ there - those errors are automatically converted into `FieldError`.
 
 When a field returns an error, the field's result is replaced by `null`, an
 additional `errors` object is created at the top level of the response, and the
-execution is resumed. If an error is returned from a non-null field, such as the
+execution is resumed. For example, with the previous example and the following
+query:
+
+```graphql
+{
+  example {
+    contents
+    foo
+  }
+}
+```
+
+If `str::from_utf8` resulted in a `std::str::Utf8Error`, the following would be
+returned:
+
+!FILENAME Response for nullable field with error
+
+```js
+{
+  "data": {
+    "example": {
+      contents: "<Contents of the file>",
+      foo: null,
+    }
+  },
+  "errors": [
+    "message": "invalid utf-8 sequence of 2 bytes from index 0",
+    "locations": [{ "line": 2, "column": 4 }])
+  ]
+}
+```
+
+If an error is returned from a non-null field, such as the
 example above, the `null` value is propagated up to the first nullable parent
 field, or the root `data` object if there are no nullable fields.
+
+For example, with the following query:
+
+```graphql
+{
+  example {
+    contents
+  }
+}
+```
+
+If `File::open()` above resulted in `std::io::ErrorKind::PermissionDenied`, the
+following would be returned:
+
+!FILENAME Response for non-null field with error and no nullable parent
+
+```js
+{
+  "errors": [
+    "message": "Permission denied (os error 13)",
+    "locations": [{ "line": 2, "column": 4 }])
+  ]
+}
+```
+
+## Structured errors
+
+Sometimes it is desirable to return additional structured error information
+to clients. This can be accomplished by implementing [`IntoFieldError`](https://docs.rs/juniper/latest/juniper/trait.IntoFieldError.html):
+
+```rust
+# #[macro_use] extern crate juniper;
+use juniper::{FieldError, IntoFieldError};
+
+enum CustomError {
+    WhateverNotSet,
+}
+
+impl IntoFieldError for CustomError {
+    fn into_field_error(self) -> FieldError {
+        match self {
+            CustomError::WhateverNotSet => FieldError::new(
+                "Whatever does not exist",
+                graphql_value!({
+                    "type": "NO_WHATEVER"
+                }),
+            ),
+        }
+    }
+}
+
+struct Example {
+    whatever: Option<bool>,
+}
+
+graphql_object!(Example: () |&self| {
+    field whatever() -> Result<bool, CustomError> {
+      if let Some(value) = self.whatever {
+        return Ok(value);
+      }
+      Err(CustomError::WhateverNotSet)
+    }
+});
+
+# fn main() {}
+```
+
+The specified structured error information is included in the [`extensions`](https://facebook.github.io/graphql/June2018/#sec-Errors) key:
+
+```js
+{
+  "errors": [
+    "message": "Whatever does not exist",
+    "locations": [{ "line": 2, "column": 4 }]),
+    "extensions": {
+      "type": "NO_WHATEVER"
+    }
+  ]
+}
+```
diff --git a/package.json b/package.json
index 1774560..2a27422 100644
--- a/package.json
+++ b/package.json
@@ -4,8 +4,8 @@
   "main": "index.js",
   "license": "MIT",
   "scripts": {
-    "build": "gitbook build",
-    "serve": "gitbook serve",
+    "build": "gitbook install && gitbook build",
+    "serve": "gitbook install && gitbook serve",
     "test": "(cd _skeptic && cargo test)"
   },
   "dependencies": {
