(book) impl_object refactor
This commit is contained in:
parent
bf50c3eb86
commit
693405afa5
14 changed files with 164 additions and 111 deletions
|
@ -30,9 +30,6 @@ 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.
|
||||
|
@ -47,11 +44,14 @@ impl juniper::Context for Context {}
|
|||
|
||||
struct Query;
|
||||
|
||||
juniper::graphql_object!(Query: Context |&self| {
|
||||
field example(&executor, id: String) -> FieldResult<Example> {
|
||||
#[juniper::impl_object(
|
||||
Context = Context,
|
||||
)]
|
||||
impl Query {
|
||||
fn example(id: String) -> FieldResult<Example> {
|
||||
unimplemented!()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
type Schema = juniper::RootNode<'static, Query, EmptyMutation<Context>>;
|
||||
|
||||
|
|
|
@ -23,21 +23,22 @@ enum SignUpResult {
|
|||
Error(Vec<ValidationError>),
|
||||
}
|
||||
|
||||
juniper::graphql_object!(SignUpResult: () |&self| {
|
||||
field user() -> Option<&User> {
|
||||
#[juniper::impl_object]
|
||||
impl SignUpResult {
|
||||
fn user(&self) -> Option<&User> {
|
||||
match *self {
|
||||
SignUpResult::Ok(ref user) => Some(user),
|
||||
SignUpResult::Error(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
field error() -> Option<&Vec<ValidationError>> {
|
||||
fn error(&self) -> Option<&Vec<ValidationError>> {
|
||||
match *self {
|
||||
SignUpResult::Ok(_) => None,
|
||||
SignUpResult::Error(ref errors) => Some(errors)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
```
|
||||
|
|
|
@ -25,25 +25,31 @@ struct ValidationError {
|
|||
# #[allow(dead_code)]
|
||||
struct MutationResult<T>(Result<T, Vec<ValidationError>>);
|
||||
|
||||
juniper::graphql_object!(MutationResult<User>: () as "UserResult" |&self| {
|
||||
field user() -> Option<&User> {
|
||||
#[juniper::impl_object(
|
||||
name = "UserResult",
|
||||
)]
|
||||
impl MutationResult<User> {
|
||||
fn user(&self) -> Option<&User> {
|
||||
self.0.as_ref().ok()
|
||||
}
|
||||
|
||||
field error() -> Option<&Vec<ValidationError>> {
|
||||
fn error(&self) -> Option<&Vec<ValidationError>> {
|
||||
self.0.as_ref().err()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
juniper::graphql_object!(MutationResult<ForumPost>: () as "ForumPostResult" |&self| {
|
||||
field forum_post() -> Option<&ForumPost> {
|
||||
#[juniper::impl_object(
|
||||
name = "ForumPostResult",
|
||||
)]
|
||||
impl MutationResult<ForumPost> {
|
||||
fn forum_post(&self) -> Option<&ForumPost> {
|
||||
self.0.as_ref().ok()
|
||||
}
|
||||
|
||||
field error() -> Option<&Vec<ValidationError>> {
|
||||
fn error(&self) -> Option<&Vec<ValidationError>> {
|
||||
self.0.as_ref().err()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
```
|
||||
|
|
|
@ -20,7 +20,7 @@ naturally map to GraphQL features, such as `Option<T>`, `Vec<T>`, `Box<T>`,
|
|||
|
||||
For more advanced mappings, Juniper provides multiple macros to map your Rust
|
||||
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
|
||||
[impl_object][jp_impl_object] procedural macro that is used for declaring an object with
|
||||
resolvers, which you will use for the `Query` and `Mutation` roots.
|
||||
|
||||
```rust
|
||||
|
@ -60,7 +60,7 @@ struct NewHuman {
|
|||
}
|
||||
|
||||
// Now, we create our root Query and Mutation types with resolvers by using the
|
||||
// graphql_object! macro.
|
||||
// impl_object macro.
|
||||
// Objects can have contexts that allow accessing shared state like a database
|
||||
// pool.
|
||||
|
||||
|
@ -74,17 +74,23 @@ impl juniper::Context for Context {}
|
|||
|
||||
struct Query;
|
||||
|
||||
juniper::graphql_object!(Query: Context |&self| {
|
||||
#[juniper::impl_object(
|
||||
// Here we specify the context type for the object.
|
||||
// We need to do this in every type that
|
||||
// needs access to the context.
|
||||
Context = Context,
|
||||
)]
|
||||
impl Query {
|
||||
|
||||
field apiVersion() -> &str {
|
||||
fn apiVersion() -> &str {
|
||||
"1.0"
|
||||
}
|
||||
|
||||
// Arguments to resolvers can either be simple types or input objects.
|
||||
// The executor is a special (optional) argument that allows accessing the context.
|
||||
field human(&executor, id: String) -> FieldResult<Human> {
|
||||
// Get the context from the executor.
|
||||
let context = executor.context();
|
||||
// To gain access to the context, we specify a argument
|
||||
// that is a reference to the Context type.
|
||||
// Juniper automatically injects the correct context here.
|
||||
fn human(context: &Context, id: String) -> FieldResult<Human> {
|
||||
// Get a db connection.
|
||||
let connection = context.pool.get_connection()?;
|
||||
// Execute a db query.
|
||||
|
@ -93,18 +99,23 @@ juniper::graphql_object!(Query: Context |&self| {
|
|||
// Return the result.
|
||||
Ok(human)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Now, we do the same for our Mutation type.
|
||||
|
||||
struct Mutation;
|
||||
|
||||
juniper::graphql_object!(Mutation: Context |&self| {
|
||||
#[juniper::impl_object(
|
||||
Context = Context,
|
||||
)]
|
||||
impl Mutation {
|
||||
|
||||
field createHuman(&executor, new_human: NewHuman) -> FieldResult<Human> {
|
||||
fn createHuman(context: &Context, new_human: NewHuman) -> FieldResult<Human> {
|
||||
let db = executor.context().pool.get_connection()?;
|
||||
let human: Human = db.insert_human(&new_human)?;
|
||||
Ok(human)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// A root schema consists of a query and a mutation.
|
||||
// Request queries can be executed against a RootNode.
|
||||
|
@ -130,6 +141,7 @@ You can invoke `juniper::execute` directly to run a GraphQL query:
|
|||
# #[macro_use] extern crate juniper;
|
||||
use juniper::{FieldResult, Variables, EmptyMutation};
|
||||
|
||||
|
||||
#[derive(juniper::GraphQLEnum, Clone, Copy)]
|
||||
enum Episode {
|
||||
NewHope,
|
||||
|
@ -137,18 +149,23 @@ enum Episode {
|
|||
Jedi,
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
juniper::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);
|
||||
|
||||
impl juniper::Context for Ctx {}
|
||||
|
||||
struct Query;
|
||||
|
||||
#[juniper::impl_object(
|
||||
Context = Ctx,
|
||||
)]
|
||||
impl Query {
|
||||
fn favoriteEpisode(context: &Ctx) -> FieldResult<Episode> {
|
||||
Ok(context.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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>>;
|
||||
|
@ -181,4 +198,4 @@ fn main() {
|
|||
[rocket]: servers/rocket.md
|
||||
[iron]: servers/iron.md
|
||||
[tutorial]: ./tutorial.html
|
||||
[jp_obj_macro]: https://docs.rs/juniper/latest/juniper/macro.graphql_object.html
|
||||
[jp_obj_macro]: https://docs.rs/juniper/latest/juniper/macro.impl_object.html
|
||||
|
|
|
@ -20,19 +20,20 @@ object somewhere but never references 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!` macro:
|
||||
object in Juniper, most commonly using the `impl_object` proc macro:
|
||||
|
||||
```rust
|
||||
# use juniper::FieldResult;
|
||||
# #[derive(juniper::GraphQLObject)] struct User { name: String }
|
||||
struct Root;
|
||||
|
||||
juniper::graphql_object!(Root: () |&self| {
|
||||
field userWithUsername(username: String) -> FieldResult<Option<User>> {
|
||||
#[juniper::impl_object]
|
||||
impl Root {
|
||||
fn userWithUsername(username: String) -> FieldResult<Option<User>> {
|
||||
// Look up user in database...
|
||||
# unimplemented!()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() { }
|
||||
```
|
||||
|
@ -47,12 +48,13 @@ usually performs some mutating side-effect, such as updating a database.
|
|||
# #[derive(juniper::GraphQLObject)] struct User { name: String }
|
||||
struct Mutations;
|
||||
|
||||
juniper::graphql_object!(Mutations: () |&self| {
|
||||
field signUpUser(name: String, email: String) -> FieldResult<User> {
|
||||
#[juniper::impl_object]
|
||||
impl Mutations {
|
||||
fn signUpUser(name: String, email: String) -> FieldResult<User> {
|
||||
// Validate inputs and save user in database...
|
||||
# unimplemented!()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() { }
|
||||
```
|
||||
|
|
|
@ -47,11 +47,12 @@ fn context_factory(_: &mut Request) -> IronResult<()> {
|
|||
|
||||
struct Root;
|
||||
|
||||
juniper::graphql_object!(Root: () |&self| {
|
||||
field foo() -> String {
|
||||
#[juniper::impl_object]
|
||||
impl Root {
|
||||
fn foo() -> String {
|
||||
"Bar".to_owned()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# #[allow(unreachable_code, unused_variables)]
|
||||
fn main() {
|
||||
|
@ -98,13 +99,14 @@ fn context_factory(req: &mut Request) -> IronResult<Context> {
|
|||
|
||||
struct Root;
|
||||
|
||||
juniper::graphql_object!(Root: Context |&self| {
|
||||
field my_addr(&executor) -> String {
|
||||
let context = executor.context();
|
||||
|
||||
#[juniper::impl_object(
|
||||
Context = Context,
|
||||
)]
|
||||
impl Root {
|
||||
field my_addr(context: &Context) -> String {
|
||||
format!("Hello, you're coming from {}", context.remote_addr)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() {
|
||||
# let _graphql_endpoint = juniper_iron::GraphQLHandler::new(
|
||||
|
@ -115,10 +117,6 @@ juniper::graphql_object!(Root: Context |&self| {
|
|||
# }
|
||||
```
|
||||
|
||||
## Accessing global data
|
||||
|
||||
FIXME: Show how the `persistent` crate works with contexts using e.g. `r2d2`.
|
||||
|
||||
[iron]: http://ironframework.io
|
||||
[graphiql]: https://github.com/graphql/graphiql
|
||||
[mount]: https://github.com/iron/mount
|
||||
|
|
|
@ -14,12 +14,14 @@ struct Coordinate {
|
|||
struct Root;
|
||||
# #[derive(juniper::GraphQLObject)] struct User { name: String }
|
||||
|
||||
juniper::graphql_object!(Root: () |&self| {
|
||||
field users_at_location(coordinate: Coordinate, radius: f64) -> Vec<User> {
|
||||
#[juniper::impl_object]
|
||||
impl Root {
|
||||
fn users_at_location(coordinate: Coordinate, radius: f64) -> Vec<User> {
|
||||
// Send coordinate to database
|
||||
// ...
|
||||
# unimplemented!()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
```
|
||||
|
@ -43,12 +45,14 @@ struct WorldCoordinate {
|
|||
struct Root;
|
||||
# #[derive(juniper::GraphQLObject)] struct User { name: String }
|
||||
|
||||
juniper::graphql_object!(Root: () |&self| {
|
||||
field users_at_location(coordinate: WorldCoordinate, radius: f64) -> Vec<User> {
|
||||
#[juniper::impl_object]
|
||||
impl Root {
|
||||
fn users_at_location(coordinate: WorldCoordinate, radius: f64) -> Vec<User> {
|
||||
// Send coordinate to database
|
||||
// ...
|
||||
# unimplemented!()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
```
|
||||
|
|
|
@ -49,7 +49,7 @@ impl Character for Droid {
|
|||
fn as_droid(&self) -> Option<&Droid> { Some(&self) }
|
||||
}
|
||||
|
||||
juniper::graphql_interface!(<'a> &'a Character: () as "Character" where Scalar = <S>|&self| {
|
||||
juniper::graphql_interface!(<'a> &'a Character: () as "Character" where Scalar = <S> |&self| {
|
||||
field id() -> &str { self.id() }
|
||||
|
||||
instance_resolvers: |_| {
|
||||
|
@ -79,14 +79,14 @@ we'll use two hashmaps, but this could be two tables and some SQL calls instead:
|
|||
```rust
|
||||
# use std::collections::HashMap;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(Context = "Database")]
|
||||
#[graphql(Context = Database)]
|
||||
struct Human {
|
||||
id: String,
|
||||
home_planet: String,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(Context = "Database")]
|
||||
#[graphql(Context = Database)]
|
||||
struct Droid {
|
||||
id: String,
|
||||
primary_function: String,
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
If you've got a struct that can't be mapped directly to GraphQL, that contains
|
||||
computed fields or circular structures, you have to use a more powerful tool:
|
||||
the `graphql_object!` macro. This macro lets you define GraphQL objects similar
|
||||
to how you define methods in a Rust `impl` block for a type. Continuing with the
|
||||
the `impl_object` procedural macro. This macro lets you define GraphQL object
|
||||
fields in a Rust `impl` block for a type. Continuing with the
|
||||
example from the last chapter, this is how you would define `Person` using the
|
||||
macro:
|
||||
|
||||
|
@ -14,15 +14,16 @@ struct Person {
|
|||
age: i32,
|
||||
}
|
||||
|
||||
juniper::graphql_object!(Person: () |&self| {
|
||||
field name() -> &str {
|
||||
#[juniper::impl_object]
|
||||
impl Person {
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
field age() -> i32 {
|
||||
fn age(&self) -> i32 {
|
||||
self.age
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() { }
|
||||
```
|
||||
|
@ -42,12 +43,13 @@ struct House {
|
|||
inhabitants: Vec<Person>,
|
||||
}
|
||||
|
||||
juniper::graphql_object!(House: () |&self| {
|
||||
#[juniper::impl_object]
|
||||
impl House {
|
||||
// Creates the field inhabitantWithName(name), returning a nullable person
|
||||
field inhabitant_with_name(name: String) -> Option<&Person> {
|
||||
fn inhabitant_with_name(&self, name: String) -> Option<&Person> {
|
||||
self.inhabitants.iter().find(|p| p.name == name)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
```
|
||||
|
@ -68,15 +70,19 @@ struct Person {
|
|||
website_url: String,
|
||||
}
|
||||
|
||||
juniper::graphql_object!(Person: () as "PersonObject" |&self| {
|
||||
field name() -> &str {
|
||||
#[juniper::impl_object(
|
||||
// With this attribtue you can change the public GraphQL name of the type.
|
||||
name = "PersonObject",
|
||||
)]
|
||||
impl Person {
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
field websiteURL() -> &str {
|
||||
fn websiteURL(&self) -> &str {
|
||||
self.website_url.as_str()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() { }
|
||||
```
|
||||
|
@ -90,4 +96,4 @@ GraphQL fields expose more features than Rust's standard method syntax gives us:
|
|||
* Per-argument descriptions
|
||||
|
||||
These, and more features, are described more thorougly in [the reference
|
||||
documentation](https://docs.rs/juniper/0.8.1/juniper/macro.graphql_object.html).
|
||||
documentation](https://docs.rs/juniper/latest/juniper/macro.impl_object.html).
|
||||
|
|
|
@ -154,7 +154,7 @@ attribute:
|
|||
struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
#[graphql(deprecation="Please use the name field instead")]
|
||||
#[graphql(deprecated = "Please use the name field instead")]
|
||||
first_name: String,
|
||||
}
|
||||
|
||||
|
|
|
@ -25,14 +25,16 @@ struct Example {
|
|||
filename: PathBuf,
|
||||
}
|
||||
|
||||
juniper::graphql_object!(Example: () |&self| {
|
||||
field contents() -> FieldResult<String> {
|
||||
#[juniper::impl_object]
|
||||
impl Example {
|
||||
fn contents() -> FieldResult<String> {
|
||||
let mut file = File::open(&self.filename)?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
Ok(contents)
|
||||
}
|
||||
field foo() -> FieldResult<Option<String>> {
|
||||
|
||||
fn foo() -> FieldResult<Option<String>> {
|
||||
// Some invalid bytes.
|
||||
let invalid = vec![128, 223];
|
||||
|
||||
|
@ -41,7 +43,7 @@ juniper::graphql_object!(Example: () |&self| {
|
|||
Err(e) => Err(e)?,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
```
|
||||
|
@ -141,14 +143,15 @@ struct Example {
|
|||
whatever: Option<bool>,
|
||||
}
|
||||
|
||||
juniper::graphql_object!(Example: () |&self| {
|
||||
field whatever() -> Result<bool, CustomError> {
|
||||
#[juniper::impl_object]
|
||||
impl Example {
|
||||
fn whatever() -> Result<bool, CustomError> {
|
||||
if let Some(value) = self.whatever {
|
||||
return Ok(value);
|
||||
}
|
||||
Err(CustomError::WhateverNotSet)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
```
|
||||
|
|
|
@ -31,42 +31,57 @@ We would like a `friends` field on `User` that returns a list of `User` objects.
|
|||
In order to write such a field though, the database must be queried.
|
||||
|
||||
To solve this, we mark the `Database` as a valid context type and assign it to
|
||||
the user object. Then, we use the special `&executor` argument to access the
|
||||
current context object:
|
||||
the user object.
|
||||
|
||||
To gain access to the context, we need to specify an argument with the same
|
||||
type as the specified `Context` for the type:
|
||||
|
||||
|
||||
```rust
|
||||
# use std::collections::HashMap;
|
||||
extern crate juniper;
|
||||
|
||||
// This struct represents our context.
|
||||
struct Database {
|
||||
users: HashMap<i32, User>,
|
||||
}
|
||||
|
||||
// Mark the Database as a valid context type for Juniper
|
||||
impl juniper::Context for Database {}
|
||||
|
||||
struct User {
|
||||
id: i32,
|
||||
name: String,
|
||||
friend_ids: Vec<i32>,
|
||||
}
|
||||
|
||||
// 1. Mark the Database as a valid context type for Juniper
|
||||
impl juniper::Context for Database {}
|
||||
|
||||
// 2. Assign Database as the context type for User
|
||||
juniper::graphql_object!(User: Database |&self| {
|
||||
// 3. Use the special executor argument
|
||||
field friends(&executor) -> Vec<&User> {
|
||||
// 4. Use the executor to access the context object
|
||||
let database = executor.context();
|
||||
// Assign Database as the context type for User
|
||||
#[juniper::impl_object(
|
||||
Context = Database,
|
||||
)]
|
||||
impl User {
|
||||
// 3. Inject the context by specifying an argument
|
||||
// with the context type.
|
||||
// Note:
|
||||
// - the type must be a reference
|
||||
// - the name of the argument SHOULD be context
|
||||
fn friends(&self, context: &Database) -> Vec<&User> {
|
||||
|
||||
// 5. Use the database to lookup users
|
||||
self.friend_ids.iter()
|
||||
.map(|id| database.users.get(id).expect("Could not find user with ID"))
|
||||
.map(|id| context.users.get(id).expect("Could not find user with ID"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
field name() -> &str { self.name.as_str() }
|
||||
field id() -> i32 { self.id }
|
||||
});
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
fn id(&self) -> i32 {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
# fn main() { }
|
||||
```
|
||||
|
|
|
@ -42,7 +42,7 @@ impl Character for Droid {
|
|||
fn as_droid(&self) -> Option<&Droid> { Some(&self) }
|
||||
}
|
||||
|
||||
juniper::graphql_union!(<'a> &'a Character: () as "Character" where Scalar = <S> |&self| {
|
||||
juniper::graphql_union!(<'a> &'a Character: () as "Character" where Scalar = <S> |&self| {
|
||||
instance_resolvers: |_| {
|
||||
// The left hand side indicates the concrete type T, the right hand
|
||||
// side should be an expression returning Option<T>
|
||||
|
@ -61,14 +61,14 @@ FIXME: This example does not compile at the moment
|
|||
```rust
|
||||
# use std::collections::HashMap;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(Context = "Database")]
|
||||
#[graphql(Context = Database)]
|
||||
struct Human {
|
||||
id: String,
|
||||
home_planet: String,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(Context = "Database")]
|
||||
#[graphql(Context = Database)]
|
||||
struct Droid {
|
||||
id: String,
|
||||
primary_function: String,
|
||||
|
@ -108,14 +108,14 @@ juniper::graphql_union!(<'a> &'a Character: Database as "Character" where Scalar
|
|||
```rust
|
||||
# use std::collections::HashMap;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(Context = "Database")]
|
||||
#[graphql(Context = Database)]
|
||||
struct Human {
|
||||
id: String,
|
||||
home_planet: String,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(Context = "Database")]
|
||||
#[graphql(Context = Database)]
|
||||
struct Droid {
|
||||
id: String,
|
||||
primary_function: String,
|
||||
|
|
|
@ -6,13 +6,14 @@ edition = "2018"
|
|||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
juniper = { version = "0.11", path = "../../../juniper" }
|
||||
juniper_iron = { version = "0.3", path = "../../../juniper_iron" }
|
||||
juniper = { path = "../../../juniper" }
|
||||
juniper_iron = { path = "../../../juniper_iron" }
|
||||
|
||||
iron = "^0.5.0"
|
||||
mount = "^0.3.0"
|
||||
|
||||
skeptic = "0.13"
|
||||
serde_json = "1.0.39"
|
||||
|
||||
[build-dependencies]
|
||||
skeptic = "0.13"
|
||||
|
|
Loading…
Reference in a new issue