Updated book for master ***NO_CI***

This commit is contained in:
Juniper Bot 2019-06-25 17:02:41 +00:00
parent e4f385b088
commit 0853582b4f
4 changed files with 192 additions and 80 deletions

View file

@ -1201,40 +1201,14 @@ strings, and booleans. You can create custom scalars to other primitive values,
but this often requires coordination with the client library intended to consume but this often requires coordination with the client library intended to consume
the API you're building.</p> the API you're building.</p>
<p>Since any value going over the wire is eventually transformed into JSON, you're <p>Since any value going over the wire is eventually transformed into JSON, you're
also limited in the data types you can use. Typically, you represent your custom also limited in the data types you can use.</p>
scalars as strings.</p> <p>There are two ways to define custom scalars.</p>
<p>In Juniper, you use the <code>graphql_scalar!</code> macro to create a custom scalar. In <ul>
this example, we're representing a user ID as a string wrapped in a custom type:</p> <li>For simple scalars that just wrap a primitive type, you can use the newtype pattern with
<pre><pre class="playpen"><code class="language-rust">use juniper::Value; a custom derive.</li>
<li>For more advanced use cases with custom validation, you can use
struct UserID(String); the <code>graphql_scalar!</code> macro.</li>
</ul>
juniper::graphql_scalar!(UserID where Scalar = &lt;S&gt; {
description: &quot;An opaque identifier, represented as a string&quot;
resolve(&amp;self) -&gt; Value {
Value::scalar(self.0.clone())
}
from_input_value(v: &amp;InputValue) -&gt; Option&lt;UserID&gt; {
// If there's a parse error here, simply return None. Juniper will
// present an error to the client.
v.as_scalar_value::&lt;String&gt;().map(|s| UserID(s.to_owned()))
}
from_str&lt;'a&gt;(value: ScalarToken&lt;'a&gt;) -&gt; juniper::ParseScalarResult&lt;'a, S&gt; {
&lt;String as juniper::ParseScalarValue&lt;S&gt;&gt;::from_str(value)
}
});
#[derive(juniper::GraphQLObject)]
struct User {
id: UserID,
username: String,
}
# fn main() {}
</code></pre></pre>
<a class="header" href="#built-in-scalars" id="built-in-scalars"><h2>Built-in scalars</h2></a> <a class="header" href="#built-in-scalars" id="built-in-scalars"><h2>Built-in scalars</h2></a>
<p>Juniper has built-in support for:</p> <p>Juniper has built-in support for:</p>
<ul> <ul>
@ -1246,11 +1220,93 @@ struct User {
spec</a> as a type that is serialized spec</a> as a type that is serialized
as a string but can be parsed from both a string and an integer.</li> as a string but can be parsed from both a string and an integer.</li>
</ul> </ul>
<a class="header" href="#non-standard-scalars" id="non-standard-scalars"><h3>Non-standard scalars</h3></a> <p><strong>Third party types</strong>:</p>
<p>Juniper has built-in support for UUIDs from the <a href="https://doc.rust-lang.org/uuid/uuid/index.html">uuid <p>Juniper has built-in support for a few additional types from common third party
crate</a>. This support is enabled crates. They are enabled via features that are on by default.</p>
by default, but can be disabled if you want to reduce the number of dependencies <ul>
in your application.</p> <li>uuid::Uuid</li>
<li>chrono::DateTime</li>
<li>url::Url</li>
</ul>
<a class="header" href="#newtype-pattern" id="newtype-pattern"><h2>newtype pattern</h2></a>
<p>Often, you might need a custom scalar that just wraps an existing type.</p>
<p>This can be done with the newtype pattern and a custom derive, similar to how
serde supports this pattern with <code>#[serde(transparent)]</code>.</p>
<pre><pre class="playpen"><code class="language-rust">#[derive(juniper::GraphQLScalarValue)]
pub struct UserId(i32);
#[derive(juniper::GraphQLObject)]
struct User {
id: UserId,
}
# fn main() {}
</code></pre></pre>
<p>That's it, you can now user <code>UserId</code> in your schema.</p>
<p>The macro also allows for more customization:</p>
<pre><pre class="playpen"><code class="language-rust">/// You can use a doc comment to specify a description.
#[derive(juniper::GraphQLScalarValue)]
#[graphql(
transparent,
// Overwrite the GraphQL type name.
name = &quot;MyUserId&quot;,
// Specify a custom description.
// A description in the attribute will overwrite a doc comment.
description = &quot;My user id description&quot;,
)]
pub struct UserId(i32);
# fn main() {}
</code></pre></pre>
<a class="header" href="#custom-scalars" id="custom-scalars"><h2>Custom scalars</h2></a>
<p>For more complex situations where you also need custom parsing or validation,
you can use the <code>graphql_scalar!</code> macro.</p>
<p>Typically, you represent your custom scalars as strings.</p>
<p>The example below implements a custom scalar for a custom <code>Date</code> type.</p>
<p>Note: juniper already has built-in support for the <code>chrono::DateTime</code> type
via <code>chrono</code> feature, which is enabled by default and should be used for this
purpose.</p>
<p>The example below is used just for illustration.</p>
<p><strong>Note</strong>: the example assumes that the <code>Date</code> type implements
<code>std::fmt::Display</code> and <code>std::str::FromStr</code>.</p>
<pre><pre class="playpen"><code class="language-rust"># mod date {
# pub struct Date;
# impl std::str::FromStr for Date{
# type Err = String; fn from_str(_value: &amp;str) -&gt; Result&lt;Self, Self::Err&gt; { unimplemented!() }
# }
# // And we define how to represent date as a string.
# impl std::fmt::Display for Date {
# fn fmt(&amp;self, _f: &amp;mut std::fmt::Formatter) -&gt; std::fmt::Result {
# unimplemented!()
# }
# }
# }
use juniper::{Value, ParseScalarResult, ParseScalarValue};
use date::Date;
juniper::graphql_scalar!(Date where Scalar = &lt;S&gt; {
description: &quot;Date&quot;
// Define how to convert your custom scalar into a primitive type.
resolve(&amp;self) -&gt; Value {
Value::scalar(self.to_string())
}
// Define how to parse a primitive type into your custom scalar.
from_input_value(v: &amp;InputValue) -&gt; Option&lt;Date&gt; {
v.as_scalar_value::&lt;String&gt;()
.and_then(|s| s.parse().ok())
}
// Define how to parse a string value.
from_str&lt;'a&gt;(value: ScalarToken&lt;'a&gt;) -&gt; ParseScalarResult&lt;'a, S&gt; {
&lt;String as ParseScalarValue&lt;S&gt;&gt;::from_str(value)
}
});
# fn main() {}
</code></pre></pre>
<a class="header" href="#unions" id="unions"><h1>Unions</h1></a> <a class="header" href="#unions" id="unions"><h1>Unions</h1></a>
<p>From a server's point of view, GraphQL unions are similar to interfaces: the <p>From a server's point of view, GraphQL unions are similar to interfaces: the
only exception is that they don't contain fields on their own.</p> only exception is that they don't contain fields on their own.</p>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -142,40 +142,14 @@ strings, and booleans. You can create custom scalars to other primitive values,
but this often requires coordination with the client library intended to consume but this often requires coordination with the client library intended to consume
the API you're building.</p> the API you're building.</p>
<p>Since any value going over the wire is eventually transformed into JSON, you're <p>Since any value going over the wire is eventually transformed into JSON, you're
also limited in the data types you can use. Typically, you represent your custom also limited in the data types you can use.</p>
scalars as strings.</p> <p>There are two ways to define custom scalars.</p>
<p>In Juniper, you use the <code>graphql_scalar!</code> macro to create a custom scalar. In <ul>
this example, we're representing a user ID as a string wrapped in a custom type:</p> <li>For simple scalars that just wrap a primitive type, you can use the newtype pattern with
<pre><pre class="playpen"><code class="language-rust">use juniper::Value; a custom derive.</li>
<li>For more advanced use cases with custom validation, you can use
struct UserID(String); the <code>graphql_scalar!</code> macro.</li>
</ul>
juniper::graphql_scalar!(UserID where Scalar = &lt;S&gt; {
description: &quot;An opaque identifier, represented as a string&quot;
resolve(&amp;self) -&gt; Value {
Value::scalar(self.0.clone())
}
from_input_value(v: &amp;InputValue) -&gt; Option&lt;UserID&gt; {
// If there's a parse error here, simply return None. Juniper will
// present an error to the client.
v.as_scalar_value::&lt;String&gt;().map(|s| UserID(s.to_owned()))
}
from_str&lt;'a&gt;(value: ScalarToken&lt;'a&gt;) -&gt; juniper::ParseScalarResult&lt;'a, S&gt; {
&lt;String as juniper::ParseScalarValue&lt;S&gt;&gt;::from_str(value)
}
});
#[derive(juniper::GraphQLObject)]
struct User {
id: UserID,
username: String,
}
# fn main() {}
</code></pre></pre>
<a class="header" href="#built-in-scalars" id="built-in-scalars"><h2>Built-in scalars</h2></a> <a class="header" href="#built-in-scalars" id="built-in-scalars"><h2>Built-in scalars</h2></a>
<p>Juniper has built-in support for:</p> <p>Juniper has built-in support for:</p>
<ul> <ul>
@ -187,11 +161,93 @@ struct User {
spec</a> as a type that is serialized spec</a> as a type that is serialized
as a string but can be parsed from both a string and an integer.</li> as a string but can be parsed from both a string and an integer.</li>
</ul> </ul>
<a class="header" href="#non-standard-scalars" id="non-standard-scalars"><h3>Non-standard scalars</h3></a> <p><strong>Third party types</strong>:</p>
<p>Juniper has built-in support for UUIDs from the <a href="https://doc.rust-lang.org/uuid/uuid/index.html">uuid <p>Juniper has built-in support for a few additional types from common third party
crate</a>. This support is enabled crates. They are enabled via features that are on by default.</p>
by default, but can be disabled if you want to reduce the number of dependencies <ul>
in your application.</p> <li>uuid::Uuid</li>
<li>chrono::DateTime</li>
<li>url::Url</li>
</ul>
<a class="header" href="#newtype-pattern" id="newtype-pattern"><h2>newtype pattern</h2></a>
<p>Often, you might need a custom scalar that just wraps an existing type.</p>
<p>This can be done with the newtype pattern and a custom derive, similar to how
serde supports this pattern with <code>#[serde(transparent)]</code>.</p>
<pre><pre class="playpen"><code class="language-rust">#[derive(juniper::GraphQLScalarValue)]
pub struct UserId(i32);
#[derive(juniper::GraphQLObject)]
struct User {
id: UserId,
}
# fn main() {}
</code></pre></pre>
<p>That's it, you can now user <code>UserId</code> in your schema.</p>
<p>The macro also allows for more customization:</p>
<pre><pre class="playpen"><code class="language-rust">/// You can use a doc comment to specify a description.
#[derive(juniper::GraphQLScalarValue)]
#[graphql(
transparent,
// Overwrite the GraphQL type name.
name = &quot;MyUserId&quot;,
// Specify a custom description.
// A description in the attribute will overwrite a doc comment.
description = &quot;My user id description&quot;,
)]
pub struct UserId(i32);
# fn main() {}
</code></pre></pre>
<a class="header" href="#custom-scalars" id="custom-scalars"><h2>Custom scalars</h2></a>
<p>For more complex situations where you also need custom parsing or validation,
you can use the <code>graphql_scalar!</code> macro.</p>
<p>Typically, you represent your custom scalars as strings.</p>
<p>The example below implements a custom scalar for a custom <code>Date</code> type.</p>
<p>Note: juniper already has built-in support for the <code>chrono::DateTime</code> type
via <code>chrono</code> feature, which is enabled by default and should be used for this
purpose.</p>
<p>The example below is used just for illustration.</p>
<p><strong>Note</strong>: the example assumes that the <code>Date</code> type implements
<code>std::fmt::Display</code> and <code>std::str::FromStr</code>.</p>
<pre><pre class="playpen"><code class="language-rust"># mod date {
# pub struct Date;
# impl std::str::FromStr for Date{
# type Err = String; fn from_str(_value: &amp;str) -&gt; Result&lt;Self, Self::Err&gt; { unimplemented!() }
# }
# // And we define how to represent date as a string.
# impl std::fmt::Display for Date {
# fn fmt(&amp;self, _f: &amp;mut std::fmt::Formatter) -&gt; std::fmt::Result {
# unimplemented!()
# }
# }
# }
use juniper::{Value, ParseScalarResult, ParseScalarValue};
use date::Date;
juniper::graphql_scalar!(Date where Scalar = &lt;S&gt; {
description: &quot;Date&quot;
// Define how to convert your custom scalar into a primitive type.
resolve(&amp;self) -&gt; Value {
Value::scalar(self.to_string())
}
// Define how to parse a primitive type into your custom scalar.
from_input_value(v: &amp;InputValue) -&gt; Option&lt;Date&gt; {
v.as_scalar_value::&lt;String&gt;()
.and_then(|s| s.parse().ok())
}
// Define how to parse a string value.
from_str&lt;'a&gt;(value: ScalarToken&lt;'a&gt;) -&gt; ParseScalarResult&lt;'a, S&gt; {
&lt;String as ParseScalarValue&lt;S&gt;&gt;::from_str(value)
}
});
# fn main() {}
</code></pre></pre>
</main> </main>