GraphQL server library for Rust

Overview

Juniper

GraphQL server library for Rust

Build Status codecov Crates.io Gitter chat


GraphQL is a data query language developed by Facebook intended to serve mobile and web application frontends.

Juniper makes it possible to write GraphQL servers in Rust that are type-safe and blazingly fast. We also try to make declaring and resolving GraphQL schemas as convenient as Rust will allow.

Juniper does not include a web server - instead it provides building blocks to make integration with existing servers straightforward. It optionally provides a pre-built integration for the Actix, Hyper, Iron, Rocket, and Warp frameworks, including embedded Graphiql and GraphQL Playground for easy debugging.

The book is also available for the master branch and older versions published after 0.11.1. See the book index.

Getting Started

The best place to get started is the Juniper Book, which contains guides with plenty of examples, covering all features of Juniper. (very much WIP)

To get started quickly and get a feel for Juniper, check out the Quickstart section.

For specific information about macros, types and the Juniper api, the API Reference is the best place to look.

You can also check out the Star Wars schema to see a complex example including polymorphism with traits and interfaces. For an example of web framework integration, see the actix, hyper, rocket, iron, and warp examples folders.

Features

Juniper supports the full GraphQL query language according to the specification, including interfaces, unions, schema introspection, and validations. It can also output the schema in the GraphQL Schema Language.

As an exception to other GraphQL libraries for other languages, Juniper builds non-null types by default. A field of type Vec<Episode> will be converted into [Episode!]!. The corresponding Rust type for e.g. [Episode] would be Option<Vec<Option<Episode>>>.

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.

Integrations

Data types

Juniper has automatic integration with some very common Rust crates to make building schemas a breeze. The types from these crates will be usable in your Schemas automatically.

Web Frameworks

Guides & Examples

API Stability

Juniper has not reached 1.0 yet, thus some API instability should be expected.

Comments
  • Interop with async? (Tokio/Futures)

    Interop with async? (Tokio/Futures)

    Hi -

    Have you put any thought into how this could be used with an async IO model, such as with Tokio? Right now it seems like it's all implicitly synchronous, but perhaps it's just a matter of making the various functions take/return Futures?

    Thanks

    enhancement 
    opened by jsgf 75
  • Add subscription support

    Add subscription support

    Before merge: Resolve TODO#433 (import crates in subscriptions example from GitHub instead of local)

    Related issue: #54

    How to implement custom GraphQL subscription

    Note: by SubscriptionCoordinator and SubscriptionConnection I mean types implementing these traits

    Current execution logic is inspired with this and this idea. In a nutshell:

    When a request is received, it gets processed by a SubscriptionCoordinator. This struct decides if incoming request should be resolved into a new stream or if one of already existing streams (that coordinator knows about) is good enough. juniper_subscriptions::Coordinator resolves each request into a new stream.

    SubscriptionCoordinator should call juniper::http::resolve_into_stream each time it needs to resolve a GraphQLRequest to Value<Stream<Item = Value<S>>. If subscripiton-related macros are used, Value::Object<Stream<Item = Value<_>> is returned. It keeps each field and corresponding Stream<Item = Value<_>>. Objects can be iterated over and needed GraphQL objects can be assembled from returned Streams. When iterating over an object returned from subscription macros, each object field should be mapped to Value::Scalar<StreamT>, where StreamT is the type user has specified in field resolvers.

    #[juniper::graphql_subscription] macro implements GraphQLType + GraphQLSubscriptionType. GraphQLType is used to store which fields this subscription has, which types they have, etc. Its resolvers ( resolve, resolve_field, resolve_into_type) are not used. GraphQLSubscriptionType's resolve_into_stream (called by Executor), resolve_field_into_stream, resolve_type_into_stream (called by resolve_into_stream) are used instead.

    Once a Value<Stream> is returned from resolve_into_stream, it is returned to the user (user most probably called juniper::http::resolve_into_stream to get to resolvers and resolve a request into stream).

    Once a stream is returned, it could be put inside a SubscriptionConnection (if called by SubscriptionCoordinator). SubscriptionConnection implements Stream<Item = GraphQLResponse>. GraphQLResponse can be deserialized and sent to end user => SubscriptionConnection can be polled by server implementation. SubscriptionConnection could also have functionality for stopping, reconnecting, etc (will be implemented in the follow-up PRs).

    SubscriptionCoordinator and SubscriptionConnection are types that manage and control already obtained Streams. GraphQLSubscriptionType manages resolvers on GraphQL objects.

    Data flow in `warp_subscriptions` example

    • HTTP server is initialized with RootNode and SubscriptionCoordinator
    1. server gets a request
    2. request is deserialized into GraphQlRequest
    3. graphql_subscriptions_async(ws_connection, coordinator) - example's helper for subscription execution
      1. coordinator.subscribe(request, context) - resolve GraphQlRequest into Stream and return SubscriptionConnection containing that stream
        • juniper::http::resolve_into_stream(...) - get operation name and variables from request
        • crate::resolve_into_stream(...) - parse document, make sure no errors are found
        • executor::resolve_validated_subscription(...) - create executor and resolve subscription query into Value<Stream<Item = Value<S>>>
        • executor.resolve_into_stream(...) - check if self.subscribe has errors and push them to executor
        • self.subscribe(...) - return value.resolve_into_stream(...).
        • value.resolve_into_stream(...) - user logic how to resolve this value into stream
          • by default, each value V returned from stream is treated as a if a query was executed asynchronously and V was returned. Ongoing execution logic creates new Value::Object with fields requested by user (for example, if user {id name} was requested, each User { id name email } returned from stream will be returned as User { id name } GraphQL object)
      2. Returned SubscriptionConnection can be used as a Stream over GraphQLResponses, which can be deserialized and sent to the end user. juniper_subscriptions::Connection waits until all object's fields are resolved and then returns the whole object.
      3. Every time a GraphQlResponse is yielded from a stream, send it to end user

    Starting playground server

    • Go to examples/warp_subscriptions and cargo run. New warp server should start on localhost:8080
    • Subscription queries should be able to be executed at this point:
    subscription {
        users {
            id
            kind
            name
            friends {
                id
                kind
            }
        }
    }
    
    • New users are returned every 5 seconds. Fragments and multiple subscriptions are also supported.
    Note: playground doesn't support anonymous subscriptions referencing fragments (prisma-labs/graphql-playground/issues/1067), so the following request can be sent to `localhost:8000/subscriptions` to test it
    
    {"id":"1","type":"start","payload":{"variables":{},"extensions":{},"operationName":null,"query":"subscription { ...myFragment } fragment myFragment on Subscription { users { id name friends { id name } }"}}
    

    opened by nWacky 52
  • Redesign interfaces (#1000)

    Redesign interfaces (#1000)

    Part of #1000 Resolves #113 Partially resolves #814

    Synopsis

    Current approach to the interfaces most of the times works fine, but can't fully support GraphQL spec and may be misused.

    Solution

    • https://github.com/graphql-rust/juniper/pull/1009#issuecomment-1006369120

    Checklist

    • Created PR:
      • [x] In draft mode
      • [x] Name contains Draft: prefix
      • [x] Name contains issue reference
      • [x] Has assignee
    • [x] Documentation is updated (if required)
    • [x] Tests are updated (if required)
    • [x] Changes conform code style
    • [x] CHANGELOG entry is added (if required)
    • [x] FCM (final commit message) is posted
      • [x] and approved
    • [x] Review is completed and changes are approved
    • Before merge:
      • [x] Milestone is set
      • [x] PR's name and description are correct and up-to-date
      • [x] Draft: prefix is removed
      • [x] All temporary labels are removed
    enhancement breaking-change api 
    opened by ilslv 31
  • Implement `std::error::Error` for all error types

    Implement `std::error::Error` for all error types

    Fixes https://github.com/graphql-rust/juniper/issues/415

    • [x] GraphQLError
    • [x] ParseError
    • [x] LexerError
    • [x] RuleError
    • [x] FieldError

    I'm having some issues with FieldError. I end up hitting a conflicting implementation error when I add

    impl<S> std::error::Error for FieldError<S> {}
    
    impl<S> fmt::Display for FieldError<S> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }
    

    I get this error:

    error[E0119]: conflicting implementations of trait `std::convert::From<executor::FieldError<_>>` for type `executor::FieldError<_>`:
       --> juniper/src/executor/mod.rs:142:1
        |
    142 | / impl<T: Display, S> From<T> for FieldError<S>
    143 | | where
    144 | |     S: crate::value::ScalarValue,
    145 | | {
    ...   |
    151 | |     }
    152 | | }
        | |_^
        |
        = note: conflicting implementation in crate `core`:
                - impl<T> std::convert::From<T> for T;
    

    I'm not quite sure what is causing that.

    opened by davidpdrsn 28
  • Support subscriptions

    Support subscriptions

    Looks like subscriptions made it into the spec.

    While most users will implement subscription logic outside juniper (like how Facebook interfaces with a MQTT server handling the actual delivery and connections) it might be useful to add some integrations as optional features.

    enhancement 
    opened by LegNeato 27
  • Codegen reimplementation for GraphQL unions

    Codegen reimplementation for GraphQL unions

    Fixes #549 As side effect, also fixes #663 Also, related to #295

    Background and motivation

    TL;DR: current codegen for GraphQL unions is not much flexible and is too magic.

    • #[derive(GraphQLUnion)] macro:
      • Applicable only to enums.
      • Doesn't support generics on type, even if they're not required for type resolution.
      • Cannot work with multiple #[graphql] attributes, just pickups first and silently ignores others.
      • Not cleverly enough generates From implementations, which leads to painful conflicts.
    • #[graphql_union] macro:
      • The code being fed into macro looks like a valid Rust code, but actually is not.
      • Operates with types/traits which don't really exist (GraphQLUnion), and declares impl blocks which don't exist after macro expansion too.

    We definitelly want less magic, applying custom behavior in an ergonomic and convenient way and operate with valid Rust code for better IDE experience.

    New design

    In a nutshell, it provides a single #[derive(GraphQLUnion)] macro which allows to modify resolution logic with custom functions. This is the same what serde does with #[derive(Serialize)] macro and #[serde(with = "my_func")] attribute.

    #[derive(GraphQLUnion, derive_more::From)]
    #[graphql(name = "TheCharacter", desc = "Superb character")]
    #[graphql(context = MyContext)]  // <-- if not specified, then Context is `()`
    #[graphql(scalar = juniper::DefaultScajarValue)] // <-- if not specified, then generated code is parametrized by `__S: ScalarValue`
    #[graphql(on Jedi = Character::as_jedi)]
    #[graphql(on Jedi = Character::as_better_jedi)]  // <-- emits compile-time duplication error
    #[graphql(on Sith = Character::as_sith)]  // <-- resolution logic doesn't require the type to be a part of enum
    pub enum Character<T> {
        One(Human),  // <-- will be trivially resolved as expected
    
        #[graphql(with = Character::as_droid)]
        Two(Droid),  // <-- will be resolved with `Character::as_droid` function
    
        #[graphql(ignore)]
        #[from(ignore)]
        Three<T>,   // <-- will be skipped
    
        #[graphql(with = Character::as_jedi)]  // <-- emits compile-time duplication error
        #[from(ignore)]
        Jedi,  // <-- if custom resolver specified, the variant doesn't have to containt the single type value
    }
    
    impl<T> Character<T> {
        // We can use in fuctions as context any type which implements `FromContext<MyContext>`.
        fn as_droid(&self, _: &()) -> Option<&Droid> {
            if let Self::Two(droid) = self {
                Some(droid)
            } else {
                None
            }
        }
    
        fn as_jedi(&self, ctx: &MyContext) -> Option<&Droid> {
           ctx.can_i_haz_the_jedi_please()
        }
    
        fn as_sith(&self, ctx: &SithContext) -> Option<&Sith> {
           ctx.deploy_new_sith_here()
        }
    }
    

    All the described above is applicable in the same manner to struct types too.

    #[derive(GraphQLUnion]
    #[graphql(name = "TheCharacter", desc = "Superb character")]
    #[graphql(context = MyContext)]  // <-- if not specified, then Context is `()`
    #[graphql(scalar = juniper::DefaultScajarValue)] // <-- if not specified, then generated code is parametrized by `__S: ScalarValue`
    #[graphql(on Jedi = Character::resolve_jedi, on Sith = Character::deploy_sith)]`
    struct TheCharacter<T>(PhantomData<T>);
    
    impl<T> Character<T> {
        fn resolve_jedi(&self, ctx: &Context) -> Option<&Jedi> {
            ctx.can_i_haz_the_jedi_please()
        }
    
        fn deploy_sith(&self, ctx: &SithContext) -> Option<&Sith> {
            ctx.deploy_new_sith_here()
        }
    }
    

    Also, for enums, the innerhood From implementations are removed. It's better to used derive_more::From for that purpose, which does stuff in much more clever way, and will preserve a bit more of SRP for our macro.

    However, to support traits, we still need to provide #[graphql_union] macro, as proc_macro_derive cannot be placed on trait declarations. And to avoid collisions with #[graphql] helper attribute (which will result in compilation error), we shoud use #[graphql_union] even for methods.

    #[graphq_union(name = "Character", desc = "Traited character")]
    #[graphq_union(context = MyContext)]  // <-- if not specified, then auto-inferred from methods, if possible, otherwise is `()`
    #[graphq_union(scalar = juniper::DefaultScajarValue)] // <-- if not specified, then generated code is parametrized by `__S: ScalarValue`
    #[graphq_union(on Jedi = custom_resolve_as_jedi)]  // <-- it's possible even for traits!
    trait Character {  // <-- trait, however, needs to be object-safe as dynamic dispatch is involved
        fn as_human(&self) -> Option<&Human> { None } // <-- we can omit context here if we want
        fn as_droid(&self, _: &Context) -> Option<&Droid> { None }
        #[graphq_union(ignore)]
        fn unrelated_trait_method(&self) { }
    }
    
    impl Character for Human {
        fn as_human(&self) -> Option<&Human> {
            Some(self)
        }
    }
    
    impl Character for Droid {
        fn as_droid(&self, _: &Context) -> Option<&Droid> {
            Some(self)
        }
    }
    
    fn custom_resolve_as_jedi(ch: &dyn Character, ctx: &MyContext) -> Option<&Jedi> {
         ctx.can_i_haz_the_jedi_please(ch)
    }
    

    Also, this PR:

    • Adds juniper::marker::GraphQLUnion trait, to not reffer in the code to unexistent trait/types.
    • Relaxes Sized requirement on GraphQLType trait to allow implement it for bare trait objects.

    Features

    • Fully valid Rust code. No magic at all. All macro are additive and only add new code without transforming/removing existing.
    • Idiomatic and familiar way for handling custom logic in proc macros: #[attr(with = func_name)].
    • No need to choose between macros. There is a single macro for each situation, which still allows tweaking with custom behavior/logic.
    • Multiple #[graphql] attributes are supported.
    • Generics are supported.

    Checklist

    • [x] Support parsing multiple #[graphql] attributes.
      • [x] Duplication check inside single attribute.
      • [x] Duplication check across multiple attributes.
    • [x] Re-export futures crate inside juniper with #[doc(hidden)] for internal use in macros.
    • [x] Make GraphQLUnion a real marker trait.
    • [x] Relax Sized requirement on GraphQLType trait.
    • [x] Enums (#[derive(GraphQLUnion)]):
      • [x] infer trivial implementation for enum variants;
      • [x] support ignoring variant with #[graphq(ignore)] attribute;
      • [x] support generics in type declaration;
      • [x] support custom context type with #[graphql(context = Type)] attribute;
      • [x] support custom ScalarValue type #[graphql(scalar = Type)] attribute;
      • [x] support custom GraphQL name and description with #[graphql(name = "Type")] and #[graphql(description = "A Type desc.")] attributes;
      • [x] support custom resolvers on type itself with #[grapqh(on Type = resolver_fn)] attribute;
      • [x] support custom resolver on a type variant with #[grapqh(with = resolver_fn)] attribute;
        • [x] duplication check between #[grapqh(on Type = resolver_fn)] and #[grapqh(with = resolver_fn)] attributes for the same type;
      • [x] remove auto-generated From implementations for enum variants.
    • [x] Structs (#[derive(GraphQLUnion)]):
      • [x] support custom resolvers on type itself with #[grapqh(on Type = resolver_fn)] attribute;
      • [x] support generics in type declaration;
      • [x] support custom context type with #[graphql(context = Type)] attribute;
      • [x] support custom ScalarValue type #[graphql(scalar = Type)] attribute;
      • [x] support custom GraphQL name and description with #[graphql(name = "Type")] and #[graphql(description = "A Type desc.")] attributes.
    • [x] Traits (#[graphql_union]):
      • [x] use trait methods with return Option<&Type> as union variant resolvers;
        • [x] allow omitting Context in methods;
        • [x] work correctly with parenthesized types;
        • [x] allow full import paths as types;
        • [x] validate signature for good error messages;
      • [x] support multiple attributes
        • [x] remove duplicated attributes on first expansion
      • [x] support custom resolvers on type itself with #[graphql_union(on Type = resolver_fn)] attribute;
      • [x] support custom context type with #[graphql_union(context = Type)] attribute;
      • [x] support custom ScalarValue type #[graphql_union(scalar = Type)] attribute;
      • [x] support custom GraphQL name and description with #[graphql_union(name = "Type")] and #[graphql_union(description = "A Type desc.")] attributes;
      • [x] ignore trait methods with #[graphql_union(ignore)] attribute.
    • [x] Review tests and provide rich coverage of all situations
    • [x] Documentation and Book are updated
    • [x] Changelog is updated
    enhancement docs breaking-change api 
    opened by tyranron 24
  • Switch to Azure Pipelines

    Switch to Azure Pipelines

    AppVeyor is super flaky.

    It looks like https://azure.microsoft.com/en-us/services/devops/pipelines/ supports all platforms and would be really fast:

    "Get cloud-hosted pipelines for Linux, macOS, and Windows with unlimited minutes and 10 free parallel jobs for open source"

    We could switch to one CI instead of maintaining multiple.

    enhancement tooling 
    opened by LegNeato 23
  • Add integration crate for the warp framework

    Add integration crate for the warp framework

    I think this still needs more testing but coming up with this integration was very smooth and it feels like idiomatic warp (I've only been programming with warp since its first public release, so yesterday :)).

    I'll keep working on polishing this over the weekend (docs, tests) but feedback would still be appreciated.

    This notably does not have support for batch requests. Should it be implemented in this PR or can it be done separately?

    opened by tomhoule 23
  • πŸ”¬ Make interfaces great again!

    πŸ”¬ Make interfaces great again!

    Part of #295 Fixes #544, #605, #658, #748
    Related to #421, #2

    ...or not so great? πŸ€”

    Motivation

    We want GraphQL interfaces which just feel right like usual ones in many PLs.

    ~~They should be able to work with an open set of types without requiring a user to specify all the concrete types an interface can downcasts into on the interface side.~~
    We're unable to do that, at the moment πŸ˜•

    But we still could have a nice proc macros as convenient as they can be πŸ™ƒ

    New design

    Traits

    #[graphql_interface(enum = CharacterValue)]  // <-- use enum for dispatching
    #[graphql_interface(for = [Human, Droid, Jedi])]  // <-- mandatory =( and should enumerate all implementors
    #[graphql_interface(name = "Character", desc = "Traited character")]
    #[graphql_interface(context = MyContext)]  // <-- if not specified, then auto-inferred from methods, if possible, otherwise is `()`
    #[graphql_interface(scalar = juniper::DefaultScalarValue)] // <-- if not specified, then generated code is parametrized by `__S: ScalarValue`
    #[graphql_interface(on Jedi = custom_downcast_as_jedi)]  // <-- custom external downcaster
    trait Character {
        fn id(&self) -> &str;
    
        // Optional custom downcaster.
        #[graphql_interface(downcast)]
        fn as_droid(&self) -> Option<&Droid> { None }
    }
    
    #[graphql_interface(dyn = DynCharacter2, for = Human)]  // use trait object for dispatching
    trait Character2 {
        fn id(&self) -> &str;
    }
    
    #[derive(GraphQLObject)]
    #[graphql(implements = [CharacterValue, DynCharacter2], Context = MyContext)]
    struct Human {
        id: String,
        home_planet: String,
    }
    #[graphql_interface]
    impl Character for Human {
        fn id(&self) -> &str {
            &self.id
        }
    }
    #[graphql_interface(dyn)]  // <-- this `dyn` is inevitable when dispatching via trait objects =(
    impl Character2 for Human {
        fn id(&self) -> &str {
            &self.id
        }
    }
    
    #[derive(GraphQLObject)]
    #[graphql(implements = CharacterValue, Context = MyContext)]
    struct Droid {
        id: String,
        primary_function: String,
    }
    #[graphql_interface]
    impl Character for Droid {
        fn id(&self) -> &str {
            &self.id
        }
    
        fn as_droid(&self) -> Option<&Droid> {
            Some(self)
        }
    }
    
    
    #[derive(GraphQLObject)]
    #[graphql(implements = CharacterValue, Context = MyContext)]
    struct Jedi {
        id: String,
        rank: String,
    }
    #[graphql_interface]
    impl Character for Jedi {
        fn id(&self) -> &str {
            &self.id
        }
    }
    fn custom_downcast_as_jedi(ch: &CharacterValue, ctx: &MyContext) -> Option<&Jedi> {
         ctx.can_i_haz_the_jedi_please(ch)
    }
    

    The nearest analogue of GraphQL interfaces are, definitely, traits. However, they are a little different beasts than may seem at first glance. The main difference goes that in GraphQL interface type serves both as an abstraction and a value dispatching to concrete implementers, while in Rust, a trait is an abstraction only and you need a separate type to dispatch to a concrete implemeter, like enum or trait object, because trait is not even a type itself. This difference imposes a lot of unobvious corner cases when we try to express GraphQL interfaces in Rust. This PR tries to implement a reasonable middleground.

    So, poking with GraphQL interfaces will require two parts:

    • declare the abstraction;
    • operate ingerface's values.

    Declaring an abstraction is almost as simple as declaring trait:

    #[graphql_interface(enum = CharacterValue)]  // <-- specify type ident to represent value of interface
    #[graphql_interface(for = [Human, Droid, Jedi])]  // <-- specify implementers
    trait Character {
        fn id(&self) -> &str;
    }
    

    And then, you need to operate in a code with a Rust implementing this GraphQL interface's value:

    #[derive(GraphQLObject)]
    #[graphql(implements = CharacterValue)]  // <-- we refer here to Rust type implementing GraphQL interface, not trait
    struct Human {
        id: String,
    }
    #[graphql_interface]
    impl Character for Human {  <-- and here we're implementing GraphQL interface for Human Graphql object as a regulat trait impl
        fn id(&self) -> &str {
            &self.id
        }
    }
    

    Trait objects

    By default, an enum dispatch is used, because we should enumerate all the implementers anyway.

    However, a dyn dispatch via trait is also possible to be used. As this requires a llitle bit more code transformation and aiding during macros expansion, we shoud specify it explicitly both on the interface and the implementers:

    #[graphql_interface(dyn = DynCharacter)]  // <-- generates handy type alias for the trait object
    #[graphql_interface(for = [Human, Droid, Jedi])]  // <-- specify implementers
    trait Character {
        fn id(&self) -> &str;
    }
    
    #[derive(GraphQLObject)]
    #[graphql(implements = dyn CharacterValue)]  // <-- `dyn` part is vital here, as an underlying trait is transformed
    struct Human {
        id: String,
    }
    #[graphql_interface(dyn)]  // <-- `dyn` part is vital here, as an underlying trait is transformed
    impl Character for Human {
        fn id(&self) -> &str {
            &self.id
        }
    }
    

    Checklist

    • [x] derive(GraphQLObject)/graphql_object macros:
      • [x] support implements attribute's argument to enumerate all traits this object implements.
    • [x] Traits (#[graphql_interface(dyn)]):
      • [x] trait transformation:
        • [x] support multiple attributes and remove duplicated attributes on first expansion;
        • [x] transform trait to extend AsGraphQLValue in a object-safe manner;
          • [x] ensure trait is object safe;
        • [x] enumerate implementors with #[graphql_interface(for = [Type1, Type2])] attribute;
          • [x] ensure types are unique on type level;
          • [x] ensure types are GraphQL objects;
        • [x] support custom GraphQL name and description with #[graphql_interface(name = "Type")] and #[graphql_interface(description = "A Type desc.")] attributes;
        • [x] support custom GraphQL field deprecation with #[graphql_interface(deprecated = "Text")] attributes;
        • [x] support custom context type with #[graphql_interface(context = Type)] attribute;
          • [x] support custom names for Context argument and allow to mark it with #[graphq_interface(context)] attribute;
        • [x] support accepting executor in method arguments, optionally marked with #[graphq_interface(executor)] attribute;
        • [x] support custom ScalarValue type #[graphql_interface(scalar = Type)] attribute;
          • [x] allow explicit custom ScalarValue type patameter;
        • [x] ignore trait methods with #[graphql_interface(ignore)] attribute;
        • [x] support downcasting methods with #[graphql_interface(downcast)] attribute;
          • [x] allow omitting Context in methods;
          • [x] work correctly with parenthesized types;
          • [x] allow full import paths as types;
          • [x] validate signature for good error messages.
        • [x] support external downcasters on trait itself with #[graphql_interface(on Type = downcast_fn)] attribute;
        • [x] ~~support trivial deriving via #[graphql_interface(derive(Type))] attribute.~~ (will be implemented in a separate PR)
      • [x] impl transformation:
        • [x] ~~support custom context type with #[graphql_interface(context = Type)] attribute;~~ (not required)
        • [x] support custom ScalarValue type #[graphql_interface(scalar = Type)] attribute;
          • [x] allow explicit custom ScalarValue type patameter.
    • [x] Enums (#[graphql_interface(enum)]):
      • [x] generate enum type of all implementers;
        • [x] generate From impls to this enum for each implementer;
        • [x] impl original trait by this enum.
    enhancement docs breaking-change api 
    opened by tyranron 21
  • Ensure Specification(June 2018) Compliance

    Ensure Specification(June 2018) Compliance

    Motivation

    Juniper currently produces code which is not allowed by the GraphQL specification. To ensure that these errors are fixed, a test suite is required. The test suite ensures that configurations which are not compliant to the specification, can not successfully compile.

    Implementation

    Each GraphQL type has a Type Validation chapter. Therefore, each of the constraints must be checked. An isolated Rust source snippet is created for each of these constraints. An external library compiles these snippets. The library ensures that the output of the compilation process is equal to an expected output. With the process it is ensured that these problems can not reoccur silently in the future.

    Goals (Progress)

    • [ ] Provider better error messages
    • [ ] Ensure that everything is specification conform
    • [ ] Implement GraphQLTypeAsync for missing parts (required for the test suite)

    Related

    • https://github.com/graphql-rust/juniper/issues/630
    • https://github.com/graphql-rust/juniper/issues/627
    opened by jmpunkt 21
  • Make proc macro support parameter attributes

    Make proc macro support parameter attributes

    Fixes #421.

    I decided to add https://crates.io/crates/proc-macro-error as mentioned here. It made returning a nice error significantly easier.

    TODO

    • [x] Fix use of old style in other tests/examples. cargo test currently produces quite a few deprecation warnings.
    • [x] Make rename = "..." work. @theduke not quite sure how to handle this one. Got a hint?
    • [ ] Look into allowing docs on arguments with normal attribute https://github.com/graphql-rust/juniper/issues/525
    enhancement wontfix breaking-change api 
    opened by davidpdrsn 19
  • Why doesn't juniper_warp::make_graphql_filter take schema: Arc<RootNode<...>>?

    Why doesn't juniper_warp::make_graphql_filter take schema: Arc>?

    I notice that juniper_hyper::graphql takes the schema/rootnode argument as type Arc<RootNode<...>> but juniper_warp::make_graphql_filter only takes the schema as RootNode<...>.

    This seems to make juniper_warp difficult to use in practice in the scenario of library integrations (e.g., a juniper-based GraphQL plugin for tauri).

    In the example here this issue is side-stepped completely by creating a function schema() which returns a fresh RootNode instance.

    In a library integration, however, you do not have access to the components necessary to construct a new RootNode.

    It seems that juniper_warp should take the argument as an Arc<RootNode<...>> like juniper_hyper in order to avoid this problem.

    Is there a reason why it is not defined this way?

    integration 
    opened by silvanshade 1
  • Consistent order of definitions in Schema::as_schema_language output

    Consistent order of definitions in Schema::as_schema_language output

    Definitions in SDL created by Schema::as_schema_language appear to be sorted semi randomly. We are using this method to print SDL to a file, and this behaviour makes changes to the schema harder to review, and to navigate the file in general.

    Proposed solution

    Sort definitions in the following order:

    1. Query type
    2. Mutation type, if any
    3. Subscription type, if any
    4. All other types, sorted alphabetically

    Additional context

    Currently, the order persists between compilations as long as there are no changes to schema, but a change to one item commonly results in multiple unrelated items changing their position.

    enhancement 
    opened by nikis05 0
  • How to create a type dynamically

    How to create a type dynamically

    Hi there, thanks for this awesome library.

    Ive got two related questions its probably less messy to put in one issue, i hope thats ok.

    I want to map types to external objects (either from a json or an external python binding sourced object)

    In the docs i've found: https://graphql-rust.github.io/types/objects/complex_fields.html https://docs.rs/juniper/latest/juniper/trait.GraphQLType.html

    I'm trying to follow complex fields but can't get the import to work. Example sais: #[macro_use] extern crate juniper;

    But this won't compile for me, i have #[macro_use] in my lib.js (im making a library) but i get an error trying to use graphql_object (which im doing exactly as in the example) which is: can't find macro graphql_object in this scope.

    Is this the way to define custom types? ie. if i have a hash map i want to map over and translate the keys to fields and the values to types? (do you have any examples of this anywhere). I'm quite new to rust and the combination of graphql and rust syntax is quite intense!

    opened by happy-machine 0
  • wasm32-unknown-unknown support in non-browser environment

    wasm32-unknown-unknown support in non-browser environment

    When compiling projects targeting wasm32-unknown-unknown, dependencies on wbindgen are emitted in the wasm file.

    (import "__wbindgen_placeholder__" "__wbindgen_describe" (func $_ZN12wasm_bindgen19__wbindgen_describe17hd0bb5db14a487f56E (type $t0)))
    (import "__wbindgen_placeholder__" "__wbindgen_throw" (func $_ZN12wasm_bindgen16__wbindgen_throw17h1f7ec3f048b25bd4E (type $t10)))
    (import "__wbindgen_externref_xform__" "__wbindgen_externref_table_grow" (func $_ZN12wasm_bindgen9externref31__wbindgen_externref_table_grow17h23c6ebadcc732f10E (type $t1)))
    (import "__wbindgen_externref_xform__" "__wbindgen_externref_table_set_null" (func $_ZN12wasm_bindgen9externref35__wbindgen_externref_table_set_null17h8f133612ea24d34dE (type $t0)))
    

    In a non-browser environment, these dependencies will not be supported. A non-browser environment is a substantial use case for a graphql server (perhaps more than a browser environment), and should be supported.

    I came across this issue in the context of wasmcloud:

    [error] Failed to start actor: {:bad_return_value, {:error, "Cannot Instantiate: Link(Import(\"__wbindgen_placeholder__\", \"__wbindgen_describe\", UnknownImport(Function(FunctionType { params: [I32], results: [] }))))"}}
    

    There is a detailed discussion in the wasmcloud Slack on this issue about the time crate.

    More info

    The feature request for wasm32-uknown-unknown support from four years ago was limited to browsers with offline support. With the more recent developments in non-browser use cases, this should be revisited.

    Some versions of dependencies such as time and chrono assume that wasm-bindgen is used, and require js-sys, which is only available in browser environments. Providing proper support for non-browser environments will involve scrutinizing/pinning the dependency versions to ensure they do not suffer from this problem.

    Here are some example issues:

    • https://github.com/time-rs/time/pull/499
    • https://github.com/chronotope/chrono/issues/334

    Ultimately, it seems like the wasm and rust communities need to define more appropriate build targets to differentiate browser and non-browser targets, but until then, support needs to be gated through dependencies.

    opened by dustin-rcg 15
Owner
GraphQL Rust
GraphQL Rust
The purpose of this example is to provide details as to how one would go about using GraphQL with the Rust Language.

Zero to GraphQL Using Rust The purpose of this example is to provide details as to how one would go about using GraphQL with the Rust Language. Thus,

Conrad Taylor 1 Jan 7, 2022
Fast GraphQL CDN on Cloudflare Edge.

EdgeQL EdgeQL is a fast GraphQL CDN on Cloudflare Edge, delivering optimized GraphQL responses with low latency. Easy to use and integrate, EdgeQL lev

null 5 Apr 15, 2023
Live Server - Launch a local network server with live reload feature for static pages

Live Server - Launch a local network server with live reload feature for static pages

Lomirus 18 Nov 30, 2022
Static Web Server - a very small and fast production-ready web server suitable to serve static web files or assets

Static Web Server (or SWS abbreviated) is a very small and fast production-ready web server suitable to serve static web files or assets.

Jose Quintana 496 Jan 2, 2023
Low level HTTP server library in Rust

tiny-http Documentation Tiny but strong HTTP server in Rust. Its main objectives are to be 100% compliant with the HTTP standard and to provide an eas

null 785 Dec 29, 2022
Create, share, fetch and model Atomic Data! This project consists of a graph database + server, a CLI and a rust library.

Create, share, fetch and model Atomic Data! This repo consists of three components: A library, a server and a CLI. atomic-server Status: Beta. Breakin

Joep Meindertsma 195 Dec 28, 2022
Completely OBSOLETE Rust HTTP library (server and client)

OBSOLETION NOTICE This library is DEAD. It was a useful experiment and is now being replaced under the scope of the Teepee (experimentation grounds at

Chris Morgan 390 Dec 1, 2022
Simple http server in Rust (Windows/Mac/Linux)

How it looks like? Screenshot Command Line Arguments Simple HTTP(s) Server 0.6.1 USAGE: simple-http-server [FLAGS] [OPTIONS] [--] [root] FLAGS:

LinFeng Qian 788 Dec 28, 2022
Akasio is a simple HTTP server that redirects traffic based on a JSON redirect table. This is its Rust implementation.

This page is inaccurate and is pending updates. Akasio (Rust) Description Akasio is a simple HTTP server that redirects traffic based on a JSON redire

K4YT3X 5 May 2, 2022
simple static file server written in Rust based on axum framework

static-server simple static file server written in Rust based on axum framework I'm learning Rust and axum. My thought is simple. axum has a static-fi

null 27 Jan 1, 2023
Server with Rust, Rocket, Diesel, Docker to create your own to-do-list

Installation Install Docker & Docker-Compose Then download the repository go to the root where the Dockerfile is and do: sudo docker-compose up sudo i

Lucas Aries 3 Aug 19, 2022
Web Server made with Rust - for learning purposes

Web Server made with Rust - for learning purposes

LΓ­lian 2 Apr 25, 2022
Archibald is my attempt at learning Rust and writing a HTTP 1.1 web server.

Archibald To be a butler, is to be able to maintain an even-temper, at all times. One must have exceptional personal hygiene and look sharp and profes

Daniel Cuthbert 4 Jun 20, 2022
Salvo is a powerful and simplest web server framework in Rust world

Salvo is an extremely simple and powerful Rust web backend framework. Only basic Rust knowledge is required to develop backend services.

Salvo 1.2k Jan 5, 2023
VRS is a simple, minimal, free and open source static web server written in Rust

VRS is a simple, minimal, free and open source static web server written in Rust which uses absolutely no dependencies and revolves around Rust's std::net built-in utility.

null 36 Nov 8, 2022
A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. :zap::crab:

binserve ⚑ ?? A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. ?? UPDATE: N

Mufeed VH 722 Dec 27, 2022
Host These Things Please - a basic http server for hosting a folder fast and simply

http Host These Things Please - a basic HTTP server for hosting a folder fast and simply Selected features See the manpage for full list. Symlinks fol

thecoshman 367 Dec 23, 2022
Simple and fast web server

see Overview Simple and fast web server as a single executable with no extra dependencies required. Features Built with Tokio and Hyper TLS encryption

null 174 Dec 9, 2022
Fully async-await http server framework

Saphir is a fully async-await http server framework for rust The goal is to give low-level control to your web stack (as hyper does) without the time

Richer Archambault 83 Dec 19, 2022