async_graphql

Derive Macro Interface

source
#[derive(Interface)]
{
    // Attributes available to this derive:
    #[graphql]
}
Expand description

Define a GraphQL interface

See also the Book.

§Macro attributes

AttributedescriptionTypeOptional
nameObject namestringY
name_typeIf true, the interface name will be specified from async_graphql::TypeName traitboolY
rename_fieldsRename all the fields according to the given case convention. The possible values are “lowercase”, “UPPERCASE”, “PascalCase”, “camelCase”, “snake_case”, “SCREAMING_SNAKE_CASE”.stringY
rename_argsRename all the arguments according to the given case convention. The possible values are “lowercase”, “UPPERCASE”, “PascalCase”, “camelCase”, “snake_case”, “SCREAMING_SNAKE_CASE”.stringY
fieldFields of this InterfaceInterfaceFieldN
extendsAdd fields to an entity that’s defined in another serviceboolY
visibleIf false, it will not be displayed in introspection. See also the Book.boolY
visibleCall the specified function. If the return value is false, it will not be displayed in introspection.stringY
inaccessibleIndicate that an interface is not accessible from a supergraph when using Apollo FederationboolY
tagArbitrary string metadata that will be propagated to the supergraph when using Apollo Federation. This attribute is repeatablestringY

§Field attributes

AttributedescriptionTypeOptional
nameField namestringN
tyField typestringN
methodRust resolver method name. If specified, name will not be camelCased in schema definitionstringY
descField descriptionstringY
deprecationField deprecatedboolY
deprecationField deprecation reasonstringY
argField argumentsInterfaceFieldArgumentY
externalMark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field.boolY
providesAnnotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway.stringY
requiresAnnotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services.stringY
override_fromMark the field as overriding a field currently present on another subgraph. It is used to migrate fields between subgraphs.stringY
visibleIf false, it will not be displayed in introspection. See also the Book.boolY
visibleCall the specified function. If the return value is false, it will not be displayed in introspection.stringY
inaccessibleIndicate that a field is not accessible from a supergraph when using Apollo FederationboolY
tagArbitrary string metadata that will be propagated to the supergraph when using Apollo Federation. This attribute is repeatablestringY

§Field argument attributes

AttributedescriptionTypeOptional
nameArgument namestringN
tyArgument typestringN
descArgument descriptionstringY
defaultUse Default::default for default valuenoneY
defaultArgument default valueliteralY
default_withExpression to generate default valuecode stringY
visibleIf false, it will not be displayed in introspection. See also the Book.boolY
visibleCall the specified function. If the return value is false, it will not be displayed in introspection.stringY
secretMark this field as a secret, it will not output the actual value in the log.boolY
inaccessibleIndicate that an argument is not accessible from a supergraph when using Apollo FederationboolY
tagArbitrary string metadata that will be propagated to the supergraph when using Apollo Federation. This attribute is repeatablestringY

§Define an interface

Define TypeA, TypeB, TypeC… Implement the MyInterface

#[derive(Interface)]
enum MyInterface {
    TypeA(TypeA),
    TypeB(TypeB),
    TypeC(TypeC),
    ...
}

§Fields

The type, name, and parameter fields of the interface must exactly match the type of the implementation interface, but Result can be omitted.

use async_graphql::*;

struct TypeA {
    value: i32,
}

#[Object]
impl TypeA {
    /// Returns data borrowed from the context
    async fn value_a<'a>(&self, ctx: &'a Context<'_>) -> Result<&'a str> {
        Ok(ctx.data::<String>()?.as_str())
    }

    /// Returns data borrowed self
    async fn value_b(&self) -> &i32 {
        &self.value
    }

    /// With parameters
    async fn value_c(&self, a: i32, b: i32) -> i32 {
        a + b
    }

    /// Disabled name transformation, don't forget "method" argument in interface!
    #[graphql(name = "value_d")]
    async fn value_d(&self) -> i32 {
        &self.value + 1
    }
}

#[derive(Interface)]
#[graphql(
    field(name = "value_a", ty = "&'ctx str"),
    field(name = "value_b", ty = "&i32"),
    field(name = "value_c", ty = "i32",
        arg(name = "a", ty = "i32"),
        arg(name = "b", ty = "i32")),
    field(name = "value_d", method = "value_d", ty = "i32"),
)]
enum MyInterface {
    TypeA(TypeA)
}

struct Query;

#[Object]
impl Query {
    async fn type_a(&self) -> MyInterface {
        TypeA { value: 10 }.into()
    }
}

let schema = Schema::build(Query, EmptyMutation, EmptySubscription).data("hello".to_string()).finish();
let res = schema.execute(r#"
{
    typeA {
        valueA
        valueB
        valueC(a: 3, b: 2)
        value_d
    }
}"#).await.into_result().unwrap().data;
assert_eq!(res, value!({
    "typeA": {
        "valueA": "hello",
        "valueB": 10,
        "valueC": 5,
        "value_d": 11
    }
}));