Skip to content

Commit

Permalink
Add support for the canonical introspection schema
Browse files Browse the repository at this point in the history
Fixes graphql-rust#307.

Add support for introspection
  • Loading branch information
LegNeato committed Apr 4, 2019
1 parent 40319d9 commit 4e7fc79
Show file tree
Hide file tree
Showing 13 changed files with 2,825 additions and 21 deletions.
32 changes: 19 additions & 13 deletions docs/book/content/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@
- [Quickstart](quickstart.md)

- [Type System](types/index.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](types/other-index.md)
- [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](types/other-index.md)
- [Enums](types/enums.md)
- [Interfaces](types/interfaces.md)
- [Input objects](types/input_objects.md)
- [Scalars](types/scalars.md)
- [Unions](types/unions.md)

- [Schemas and mutations](schema/schemas_and_mutations.md)

- [Adding A Server](servers/index.md)

- [Official Server Integrations](servers/official.md) - [Hyper](servers/hyper.md)
- [Warp](servers/warp.md)
- [Rocket](servers/rocket.md)
Expand All @@ -24,8 +26,12 @@
- [Third Party Integrations](servers/third-party.md)

- [Advanced Topics](advanced/index.md)
- [Non-struct objects](advanced/non_struct_objects.md)
- [Objects and generics](advanced/objects_and_generics.md)
- [Multiple operations per request](advanced/multiple_ops_per_request.md)

- [Introspection](advanced/introspection.md)
- [Non-struct objects](advanced/non_struct_objects.md)
- [Objects and generics](advanced/objects_and_generics.md)
- [Multiple operations per request](advanced/multiple_ops_per_request.md)

# - [Context switching]

# - [Dynamic type system]
1 change: 1 addition & 0 deletions docs/book/content/advanced/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

The chapters below cover some more advanced scenarios.

- [Introspection](advanced/introspection.md)
- [Non-struct objects](advanced/non_struct_objects.md)
- [Objects and generics](advanced/objects_and_generics.md)
- [Multiple operations per request](advanced/multiple_ops_per_request.md)
73 changes: 73 additions & 0 deletions docs/book/content/advanced/introspection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Introspection

GraphQL defines a special built-in top-level field called `__schema`. Querying
for this field allows one to [inspect the schema](https://graphql.org/learn/introspection/)
at runtime to see what queries and mutations the GraphQL server supports.

Because inspection queries are just regular GraphQL queries, Juniper supports
them natively. For example, to get all the names of the types supported one
could execute the following query against Juniper:

```graphql
{
__schema {
types {
name
}
}
}
```

## Schema introspection output as JSON

Many client libraries and tools in the GraphQL ecosystem require a complete
representation of the server schema. Often this representation is in JSON and
referred to as `schema.json`. A complete representation of the schema can be
produced by issuing a specially crafted introspection query.

Juniper provides a convenience function to inspect the entire schema. The
result can then be converted to JSON for use with tools and libraries such as
[graphql-client](https://github.com/graphql-rust/graphql-client):

```rust
# // Only needed due to 2018 edition because the macro is not accessible.
# extern crate juniper;
# extern crate serde_json;
use juniper::{EmptyMutation, FieldResult, IntrospectionFormat};

// Define our schema.

#[derive(juniper::GraphQLObject)]
struct Example {
id: String,
}

struct Context;
impl juniper::Context for Context {}

struct Query;

juniper::graphql_object!(Query: Context |&self| {
field example(&executor, id: String) -> FieldResult<Example> {
unimplemented!()
}
});

type Schema = juniper::RootNode<'static, Query, EmptyMutation<Context>>;

fn main() {
// Create a context object.
let ctx = Context{};

// Run the built-in introspection query.
let (res, _errors) = juniper::introspect(
&Schema::new(Query, EmptyMutation::new()),
&ctx,
IntrospectionFormat::default(),
).unwrap();

// Convert introspection result to json.
let json_result = serde_json::to_string_pretty(&res);
assert!(json_result.is_ok());
}
```
13 changes: 8 additions & 5 deletions docs/book/content/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ 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("")? }
# fn find_human(&self, _id: &str) -> FieldResult<Human> { Err("")? }
# fn insert_human(&self, _human: &NewHuman) -> FieldResult<Human> { Err("")? }
# }

#[derive(juniper::GraphQLEnum)]
Expand Down Expand Up @@ -114,12 +114,14 @@ juniper::graphql_object!(Mutation: Context |&self| {
// Request queries can be executed against a RootNode.
type Schema = juniper::RootNode<'static, Query, Mutation>;

# fn main() { }
# fn main() {
# let _ = Schema::new(Query, Mutation{});
# }
```

We now have a very simple but functional schema for a GraphQL server!

To actually serve the schema, see the guides for our various [server integrations](./servers/index.md).
To actually serve the schema, see the guides for our various [server integrations](./servers/index.md).

You can also invoke the executor directly to get a result for a query:

Expand All @@ -129,6 +131,7 @@ You can invoke `juniper::execute` directly to run a GraphQL query:

```rust
# // Only needed due to 2018 edition because the macro is not accessible.
# #[macro_use]
# extern crate juniper;
use juniper::{FieldResult, Variables, EmptyMutation};

Expand Down Expand Up @@ -172,7 +175,7 @@ fn main() {
assert_eq!(
res,
graphql_value!({
"favoriteEpisode": "NEW_HONE",
"favoriteEpisode": "NEW_HOPE",
})
);
}
Expand Down
2 changes: 1 addition & 1 deletion docs/book/tests/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate skeptic;

fn main() {
let files = skeptic::markdown_files_of_directory("../content/types");
let files = skeptic::markdown_files_of_directory("../content/");
skeptic::generate_doc_tests(&files);
}
6 changes: 4 additions & 2 deletions juniper/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

- The minimum required Rust version is now `1.30.0`.
- The `ScalarValue` custom derive has been renamed to `GraphQLScalarValue`.
- Added built-in support for the canonical schema introspection query via
`juniper::introspect()`. [#307](https://github.com/graphql-rust/juniper/issues/307)
- Fix introspection query validity
The DirectiveLocation::InlineFragment had an invalid literal value,
which broke third party tools like apollo cli.
- Added GraphQL Playground integration
The DirectiveLocation::InlineFragment had an invalid literal value,
which broke third party tools like apollo cli.
The DirectiveLocation::InlineFragment had an invalid literal value,
which broke third party tools like apollo cli.
- The return type of `value::object::Object::iter/iter_mut` has changed to `impl Iter` [#312](https://github.com/graphql-rust/juniper/pull/312)

# [0.11.1] 2018-12-19
Expand Down
19 changes: 19 additions & 0 deletions juniper/src/introspection/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/// From <https://github.com/graphql/graphql-js/blob/8c96dc8276f2de27b8af9ffbd71a4597d483523f/src/utilities/introspectionQuery.js#L21>s
pub(crate) const INTROSPECTION_QUERY: &str = include_str!("./query.graphql");
pub(crate) const INTROSPECTION_QUERY_WITHOUT_DESCRIPTIONS: &str =
include_str!("./query_without_descriptions.graphql");

/// The desired GraphQL introspection format for the canonical query
/// (<https://github.com/graphql/graphql-js/blob/8c96dc8276f2de27b8af9ffbd71a4597d483523f/src/utilities/introspectionQuery.js#L21>)
pub enum IntrospectionFormat {
/// The canonical GraphQL introspection query.
All,
/// The canonical GraphQL introspection query without descriptions.
WithoutDescriptions,
}

impl Default for IntrospectionFormat {
fn default() -> Self {
IntrospectionFormat::All
}
}
96 changes: 96 additions & 0 deletions juniper/src/introspection/query.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
Loading

0 comments on commit 4e7fc79

Please sign in to comment.