Skip to content
This repository was archived by the owner on Mar 20, 2024. It is now read-only.

Add IntoFieldError to error docs #10

Merged
merged 6 commits into from
Sep 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
6 changes: 2 additions & 4 deletions _skeptic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }


5 changes: 1 addition & 4 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ use juniper::{FieldResult};
# fn insert_human(&self, human: &NewHuman) -> FieldResult<Human> { Err("")? }
# }


use juniper::{FieldResult};

#[derive(GraphQLEnum)]
enum Episode {
NewHope,
Expand Down Expand Up @@ -180,7 +177,7 @@ fn main() {

// Ensure the value matches.
assert_eq!(
res.as_object_value().unwrap()["favoriteEpisode"].as_string_value().unwrap(),
res.as_object_value().unwrap().get_field_value("favoriteEpisode").unwrap().as_string_value().unwrap(),
"NEW_HOPE",
);
}
Expand Down
26 changes: 13 additions & 13 deletions docs/servers/iron.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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()
}
});

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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]: http://ironframework.io
[graphiql]: https://github.com/graphql/graphiql
[mount]: https://github.com/iron/mount
124 changes: 123 additions & 1 deletion docs/types/objects/error_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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() {}
Expand All @@ -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"
}
]
}
```