Git Product home page Git Product logo

dynamic-graphql's People

Contributors

smmoosavi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

dynamic-graphql's Issues

disussion from 1248

@smmoosavi Thanks. I have checked first scenario but I wasn't able to fit it into my case. The main problem is that I have part of GQL application that is defined as in above example with MyObj (not MySimpleObj). Could you provide example scenario for that?

As far as I understand I need to rewrite all Object defined with async_graphql to be defined with dynamic_graphql? Then it's hard to go from one library to second and still keep compatible. For example below will not compile:

#[derive(Debug, async_graphql::SimpleObject, dynamic_graphql::SimpleObject)]
#[graphql(rename_fields = "camelCase")]
#[graphql(shareable)] // this will cause compiler error 
pub struct Version {
     version: String,
     name: String,
}

Also in my scenario I don't know how to use states correctly with dynamic-graphql crate ExtendedObject don't accept self as parameter.

Below I share code that compile but panic at runtime with

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SchemaError("Type \"MapperFromDynamicGraphqlToAsyncGraphql\" not found")', src/bin/gql-dynamic.rs:137:54

I would be glad if you could help me understand how can I fix it.

use async_graphql::{
    dynamic::ResolverContext,
    http::{playground_source, GraphQLPlaygroundConfig},
    Context, Object,
};

use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
use axum::{
    extract::Extension,
    response::{self, IntoResponse},
    routing::get,
    Router, Server,
};

pub type GqlResult<T> = async_graphql::Result<T>;
use dynamic_graphql::{
    dynamic, experimental::GetSchemaData, internal::Registry, ExpandObject, ExpandObjectFields,
    SimpleObject,
};

#[derive(Debug, async_graphql::SimpleObject, dynamic_graphql::SimpleObject)]
#[graphql(rename_fields = "camelCase")]
// FIXME this not works because of `dynamic_graphql::SimpleObject` #[graphql(shareable)]
pub struct Version {
    /// aplication name
    pub name: String,
    /// schematic version (semver.org)
    pub version: String,
    /// date of compilation
    pub compilation_date: Option<String>,
    /// unique hash that represent source code that was used to build
    pub compilation_hash: Option<String>,
}

pub struct AsyncGraphGqlObj {
    // inner_state will be connection to DB or other service
    inner_state: String,
}

#[Object]
impl AsyncGraphGqlObj {
    async fn name<'a>(&self, _ctx: &Context<'a>) -> &str {
        &self.inner_state
    }

    pub async fn version<'a>(&self, ctx: &Context<'a>) -> GqlResult<Vec<Version>> {
        let name = format!(
            "{}+{}",
            env!("CARGO_PKG_NAME"),
            self.name(ctx).await.unwrap().to_lowercase(),
        );
        let version = env!("CARGO_PKG_VERSION").to_string();
        let compilation_date = option_env!("VERGEN_BUILD_TIMESTAMP").map(String::from);
        let compilation_hash = option_env!("VERGEN_GIT_SHA").map(String::from);

        let gql_api_ver = Version {
            name,
            version,
            compilation_date,
            compilation_hash,
        };

        // TODO: query sth from DB where connection is keep in with &self (so inner state).

        Ok(vec![gql_api_ver])
    }
}

// this is just to make compiler happy
#[derive(SimpleObject)]
pub struct UselessButAllowCompile {}

#[derive(ExpandObject)]
struct MapperFromDynamicGraphqlToAsyncGraphql(UselessButAllowCompile);

#[ExpandObjectFields]
impl MapperFromDynamicGraphqlToAsyncGraphql {
    // just map query from dynamic-graphql to async-graphql implementation
    //
    // input parameters are here to test how they are handled by dynamic-graphql
    // more complicated requests will require parameters
    async fn version<'a>(address: String, ctx: &ResolverContext<'a>) -> GqlResult<Vec<Version>> {
        let d = ctx.get_schema_data();
        let o = d.get::<AsyncGraphGqlObj>().unwrap();

        // call async-graphql version
        o.version(ctx.ctx).await?
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();

    let registry = Registry::new()
        .register::<UselessButAllowCompile>()
        .register::<MapperFromDynamicGraphqlToAsyncGraphql>();

    let schema = dynamic::Schema::build("Query", None, None);
    let schema = registry.apply_into_schema_builder(schema);

    let query = dynamic::Object::new("Query");
    let query = query.field(dynamic::Field::new(
        "anyname",
        dynamic::TypeRef::named("MapperFromDynamicGraphqlToAsyncGraphql"),
        |_ctx| {
            /* What I am expecting here is to return Object that was defined with async_graphql*/
            // below is one of my tries to achieve it without success

            let o = MapperFromDynamicGraphqlToAsyncGraphql(UselessButAllowCompile {});
            dynamic::FieldFuture::new(async move {
                Ok(Some(
                    // depending on request this should return
                    /*
                    {
                        name: "my_inner_name_state"
                    }
                    or
                    {
                        version: {
                            name: "my_inner_name_state"
                        }
                    }
                     */
                    dynamic::FieldValue::owned_any(o).with_type("FooExpanded"),
                ))
            })
        },
    ));

    let o = AsyncGraphGqlObj {
        inner_state: String::from("my_inner_name_state"),
    };

    let schema = schema.data(o).register(query);

    let schema = schema.enable_federation().finish().unwrap();

    let app = Router::new()
        .route("/", get(graphql_playground).post(graphql_handler))
        .layer(Extension(schema));

    println!("Playground: http://localhost:8000");

    Server::bind(&"0.0.0.0:8000".parse()?)
        .serve(app.into_make_service())
        .await
        .unwrap();

    Ok(())
}

async fn graphql_handler(
    schema: Extension<async_graphql::dynamic::Schema>,
    req: GraphQLRequest,
) -> GraphQLResponse {
    let inner = req.into_inner();
    println!("req: {:?}", inner);
    schema.execute(inner).await.into()
}

async fn graphql_playground() -> impl IntoResponse {
    response::Html(playground_source(GraphQLPlaygroundConfig::new("/")))
}

Originally posted by @xoac in async-graphql/async-graphql#1248 (comment)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.