* Bootstrap * Upd * Bootstrap macro * Revert stuff * Correct PoC to compile * Bootstrap #[graphql_interface] expansion * Bootstrap #[graphql_interface] meta parsing * Bootstrap #[graphql_interface] very basic code generation [skip ci] * Upd trait code generation and fix keywords usage [skip ci] * Expand trait impls [skip ci] * Tune up objects [skip ci] * Finally! Complies at least... [skip ci] * Parse meta for fields and its arguments [skip ci] - also, refactor and bikeshed new macros code * Impl filling fields meta and bootstrap field resolution [skip ci] * Poking with fields resolution [skip ci] * Solve Rust's teen async HRTB problems [skip ci] * Start parsing trait methods [skip ci] * Finish parsing fields from trait methods [skip ci] * Autodetect trait asyncness and allow to specify it [skip ci] * Allow to autogenerate trait object alias via attribute * Support generics in trait definition and asyncify them correctly * Temporary disable explicit async * Cover arguments and custom names/descriptions in tests * Re-enable tests with explicit async and fix the codegen to satisfy it * Check implementers are registered in schema and vice versa * Check argument camelCases * Test argument defaults, and allow Into coercions for them * Re-enable markers * Re-enable markers and relax Sized requirement on IsInputType/IsOutputType marker traits * Revert 'juniper_actix' fmt * Fix missing marks for object * Fix subscriptions marks * Deduce result type correctly via traits * Final fixes * Fmt * Restore marks checking * Support custom ScalarValue * Cover deprecations with tests * Impl dowcasting via methods * Impl dowcasting via external functions * Support custom context, vol. 1 * Support custom context, vol. 2 * Cover fallible field with test * Impl explicit generic ScalarValue, vol.1 * Impl explicit generic ScalarValue, vol.2 * Allow passing executor into methods * Generating enum, vol.1 * Generating enum, vol.2 * Generating enum, vol.3 * Generating enum, vol.3 * Generating enum, vol.4 * Generating enum, vol.5 * Generating enum, vol.6 * Generating enum, vol.7 * Generating enum, vol.8 * Refactor juniper stuff * Fix juniper tests, vol.1 * Fix juniper tests, vol.2 * Polish 'juniper' crate changes, vol.1 * Polish 'juniper' crate changes, vol.2 * Remove redundant stuf * Polishing 'juniper_codegen', vol.1 * Polishing 'juniper_codegen', vol.2 * Polishing 'juniper_codegen', vol.3 * Polishing 'juniper_codegen', vol.4 * Polishing 'juniper_codegen', vol.5 * Polishing 'juniper_codegen', vol.6 * Polishing 'juniper_codegen', vol.7 * Polishing 'juniper_codegen', vol.8 * Polishing 'juniper_codegen', vol.9 * Fix other crates tests and make Clippy happier * Fix examples * Add codegen failure tests, vol. 1 * Add codegen failure tests, vol. 2 * Add codegen failure tests, vol.3 * Fix codegen failure tests accordingly to latest nightly Rust * Fix codegen when interface has no implementers * Fix warnings in book tests * Describing new interfaces in Book, vol.1 Co-authored-by: Christian Legnitto <LegNeato@users.noreply.github.com>
3.9 KiB
Schemas
Juniper follows a code-first approach to defining GraphQL schemas. If you would like to use a schema-first approach instead, consider juniper-from-schema for generating code from a schema file.
A schema consists of three types: a query object, a mutation object, and a subscription object. These three define the root query fields, mutations and subscriptions of the schema, respectively.
The usage of subscriptions is a little different from the mutation and query objects, so there is a specific section that discusses them.
Both query and mutation objects are regular GraphQL objects, defined like any other object in Juniper. The mutation and subscription objects, however, are optional since schemas can be read-only and do not require subscriptions. If mutation/subscription functionality is not needed, consider using EmptyMutation/EmptySubscription.
In Juniper, the RootNode
type represents a schema. When the schema is first created,
Juniper will traverse the entire object graph
and register all types it can find. This means that if you define a GraphQL
object somewhere but never reference it, it will not be exposed in a schema.
The query root
The query root is just a GraphQL object. You define it like any other GraphQL
object in Juniper, most commonly using the graphql_object
proc macro:
# #![allow(unused_variables)]
# extern crate juniper;
# use juniper::FieldResult;
# #[derive(juniper::GraphQLObject)] struct User { name: String }
struct Root;
#[juniper::graphql_object]
impl Root {
fn userWithUsername(username: String) -> FieldResult<Option<User>> {
// Look up user in database...
# unimplemented!()
}
}
# fn main() { }
Mutations
Mutations are also just GraphQL objects. Each mutation is a single field that performs some mutating side-effect such as updating a database.
# #![allow(unused_variables)]
# extern crate juniper;
# use juniper::FieldResult;
# #[derive(juniper::GraphQLObject)] struct User { name: String }
struct Mutations;
#[juniper::graphql_object]
impl Mutations {
fn signUpUser(name: String, email: String) -> FieldResult<User> {
// Validate inputs and save user in database...
# unimplemented!()
}
}
# fn main() { }
Converting a Rust schema to the GraphQL Schema Language
Many tools in the GraphQL ecosystem require the schema to be defined in the GraphQL Schema Language. You can generate a GraphQL Schema Language representation of your schema defined in Rust using the schema-language
feature (on by default):
# extern crate juniper;
use juniper::{FieldResult, EmptyMutation, EmptySubscription, RootNode};
struct Query;
#[juniper::graphql_object]
impl Query {
fn hello(&self) -> FieldResult<&str> {
Ok("hello world")
}
}
fn main() {
// Define our schema in Rust.
let schema = RootNode::new(
Query,
EmptyMutation::<()>::new(),
EmptySubscription::<()>::new(),
);
// Convert the Rust schema into the GraphQL Schema Language.
let result = schema.as_schema_language();
let expected = "\
type Query {
hello: String!
}
schema {
query: Query
}
";
assert_eq!(result, expected);
}
Note the schema-language
feature may be turned off if you do not need this functionality to reduce dependencies and speed up
compile times.