Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can type-graphql be used with this? #11

Open
Chrisigrimm opened this issue Feb 23, 2019 · 17 comments
Open

Can type-graphql be used with this? #11

Chrisigrimm opened this issue Feb 23, 2019 · 17 comments

Comments

@Chrisigrimm
Copy link

Hey

is there a way i can use this with type-graphql?

https://github.com/19majkel94/type-graphql

@duongdev
Copy link

I don't think it can in the near feature

@progresak
Copy link

Hey @duongdev is there any progress on this Issue? Is it somehow possible to use type-graphql with moleculer-apollo-server ? :) what are the alternatives?

@AndreMaz
Copy link
Member

@ujwal-setlur mentioned at Discord that he's using TypeGraphQL. Maybe you can ask him

@ujwal-setlur
Copy link

ujwal-setlur commented Apr 26, 2020

Yes, I am using type-graphql with apollo and moleculer. However, I am NOT using the moleculer-apollo-server package, the reason being I wanted only the API gateway to be GraphQL aware, and all other services to be pure moleculer services without any knowledge of GraphQL.

So, what I have is a moleculer service acting as an API gateway using standard apollo and type-graphql. I use type-graphql to build the GraphQL schema, queries, and resolvers. The API service essentially starts in the service's start handler the apollo server with the schema built by type-graphql. It also injects the moleculer broker into the apollo context so that queries and resolvers can access the broker via the context, and can make standard moleculer service action and event calls to other services.

graphql/index.ts

// TypeGraphQL
import 'reflect-metadata';
import { buildSchemaSync } from 'type-graphql';

// Import our GraphQL API piece by piece
// Each module here returns a TypeGraphQL resolver

// Our stuff
import { UserResolver } from './user/index';

type NonEmptyArray<TItem> = [TItem, ...TItem[]];

// Our array of resolvers
const resolvers: NonEmptyArray<Function> = [UserResolver];

// Build our schema
const schema = buildSchemaSync({ validate: false, resolvers });

// Export our schema!
export default schema;

api.service.ts

import moleculer from 'moleculer';
import { Action, Service } from 'moleculer-decorators';
import { ApolloServer } from 'apollo-server';

// Our stuff
import schema from './graphql/index'; // <-- schema built by TypeGraphQL

// Define our api service
@Service({
  name: 'api'
})
export class ApiService extends moleculer.Service {
  server!: ApolloServer;

  // Startup handler
  async started() {
    const moleculerBroker = this.broker;

    // Create our Apollo GraphQL server here
    const server = new ApolloServer({
      schema,
      context: () => ({
        moleculerBroker
      })
    });
    this.server = server;

    // Check if port is set, otherwise default to 3000
    const port = process.env.PORT || 3000;

    // Start our server
    await server.listen({ port }).then(({ url }) => {
      this.broker.logger.info(`🚀  Apollo Server ready at ${url}`);
    });
  }

  // Stopped handler
  stopped() {
    this.server.stop();
  }
}

Hope this was helpful. Happy to answer any questions.

@progresak
Copy link

@ujwal-setlur thank you so much. It actually solves my problem as well. Thanks to you I realized I need to use neither moleculer-apollo-server or moleculer-web at all since I need to have just API GraphQL backend.

@teezzan
Copy link

teezzan commented Nov 13, 2020

@ujwal-setlur I did exactly as you stated above and I ended up with Service name can't be empty! Maybe it is not a valid Service schema. Maybe is it not a service schema?. Am I doing this wrong?

@ujwal-setlur
Copy link

@teezzan I'll need to see some code snippets...

@teezzan
Copy link

teezzan commented Nov 13, 2020

Thanks for your response. My laptop is dead right now. I will share the snippets once it's up.
However, the code is as you wrote above. I was simply setting it up when it gave the error in the api.service.ts file.

@teezzan
Copy link

teezzan commented Nov 14, 2020

@ujwal-setlur Here is the code I am using currently. My aim to to get the server up and running before starting to implement the schema. The versions of some libraries are as follows.

    "reflect-metadata": "^0.1.13",
    "type-graphql": "^1.1.1",
    "typescript": "^3.8.3",
    "graphql": "^15.4.0",
    "moleculer": "^0.14.0",

LH/graphql/recipe/index.ts contains the following.

import 'reflect-metadata';
import { Field, ObjectType, Resolver, Query, Arg } from 'type-graphql';


@ObjectType({ description: "Object representing test" })
class Recipe {
    @Field()
    title: string;
}

@Resolver(Recipe)
export class RecipeResolver {
    constructor() { }

    @Query(returns => String)
    async recipe() {
        return "Hello recipe";
    }

}

LH/graphql/index.ts contains

// TypeGraphQL
import 'reflect-metadata';
import { buildSchemaSync } from 'type-graphql';

// Import our GraphQL API piece by piece
// Each module here returns a TypeGraphQL resolver

// Our stuff
import { RecipeResolver } from './recipe/index';

type NonEmptyArray<TItem> = [TItem, ...TItem[]];

// Our array of resolvers
const resolvers: NonEmptyArray<Function> = [RecipeResolver];

// Build our schema
const schema = buildSchemaSync({ validate: false, resolvers });

// Export our schema!
export default schema;

LH/services/api.service.ts contains

import moleculer from 'moleculer';
import { Action, Service } from 'moleculer-decorators';
import { ApolloServer } from 'apollo-server';

// Our stuff
import schema from '../graphql/index'; // <-- schema built by TypeGraphQL

// Define our api service
@Service({
    name: 'api'
})
export class ApiService extends moleculer.Service {
    server!: ApolloServer;

    // Startup handler
    async started() {
        const moleculerBroker = this.broker;

        // Create our Apollo GraphQL server here
        const server = new ApolloServer({
            schema,
            context: () => ({
                moleculerBroker
            })
        });
        this.server = server;

        // Check if port is set, otherwise default to 3000
        const port = process.env.PORT || 3000;

        // Start our server
        await server.listen({ port }).then(({ url }) => {
            this.broker.logger.info(`🚀  Apollo Server ready at ${url}`);
        });
    }

    // Stopped handler
    stopped() {
        this.server.stop();
    }
}

The complete error log is as follows.

[2020-11-14T16:28:11.965Z] INFO  gal1l30-inspiron-3521-6867/BROKER: Registered 14 internal middleware(s).
Service name can't be empty! Maybe it is not a valid Service schema. Maybe is it not a service schema? { schema: { ApiService: [Function] } }
[2020-11-14T16:28:19.792Z] ERROR gal1l30-inspiron-3521-6867/BROKER: Failed to load service '/home/gal3li0/Documents/Apis/bstech/LH/services/api.service.ts' ServiceSchemaError: Service name can't be empty! Maybe it is not a valid Service schema. Maybe is it not a service schema?
    at Service.parseServiceSchema (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/service.js:92:10)
    at new Service (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/service.js:63:9)
    at ServiceBroker.createService (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/service-broker.js:805:14)
    at ServiceBroker.loadService (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/service-broker.js:770:16)
    at /home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/runner.js:382:50
    at Array.forEach (<anonymous>)
    at MoleculerRunner.loadServices (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/runner.js:382:25)
    at MoleculerRunner.startBroker (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/runner.js:453:8)
    at /home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/runner.js:475:21 {
  code: 500,
  type: 'SERVICE_SCHEMA_ERROR',
  data: { schema: { ApiService: [Function] } },
  retryable: false
}
[Runner] Service name can't be empty! Maybe it is not a valid Service schema. Maybe is it not a service schema? ServiceSchemaError: Service name can't be empty! Maybe it is not a valid Service schema. Maybe is it not a service schema?
    at Service.parseServiceSchema (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/service.js:92:10)
    at new Service (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/service.js:63:9)
    at ServiceBroker.createService (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/service-broker.js:805:14)
    at ServiceBroker.loadService (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/service-broker.js:770:16)
    at /home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/runner.js:382:50
    at Array.forEach (<anonymous>)
    at MoleculerRunner.loadServices (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/runner.js:382:25)
    at MoleculerRunner.startBroker (/home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/runner.js:453:8)
    at /home/gal3li0/Documents/Apis/bstech/LH/node_modules/moleculer/src/runner.js:475:21 {
  code: 500,
  type: 'SERVICE_SCHEMA_ERROR',
  data: { schema: { ApiService: [Function] } },
  retryable: false
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dev: `ts-node ./node_modules/moleculer/bin/moleculer-runner.js --hot --repl --env --config moleculer.config.ts services/**/*.service.ts`
npm ERR! Exit status 1
npm ERR! src
npm ERR! Failed at the [email protected] dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/gal3li0/.npm/_logs/2020-11-14T16_28_19_888Z-debug.log

Thanks

@teezzan
Copy link

teezzan commented Nov 15, 2020

Thanks @ujwal-setlur and @progresak . I solved it by looking through @progresak project. I needed to add a this.name = 'api' to the started async function. I didn't think of that.

Thanks.

@teezzan
Copy link

teezzan commented Nov 15, 2020

Does anyone have any idea on how to get typegraphql authorization working? I figured it would require extracting the authorization headers from req. Unfortunately, I haven't been able to lay my hands on req at all. I tried using global Middleware but it isn't getting called at all. Any help?

@teezzan
Copy link

teezzan commented Nov 16, 2020

Solved... Apollo Server context to the rescue.
https://www.apollographql.com/docs/apollo-server/security/authentication/

Thanks

@ujwal-setlur
Copy link

ujwal-setlur commented Nov 17, 2020 via email

@iasbm
Copy link

iasbm commented Jul 22, 2022

Thanks for this thread and it kind of gives options for us to similar issue we are aiming to resolve.
The only thing we like to know is how can we handle /route a GraphQL Query ( from client) inside the API G/W ( GraphQL aware just as per the implementation samples posted by @ujwal-setlur and @teezzan ) to invoke pure Moleculer Micro Services (Not GraphQL Aware) to fulfil the GQL request by using the Resolvers please. i.e can you please clarify which of the below flow you implemented?
Flow-1 --> Client with GQL Reqeust --> API GW with Apollo server --> Moleculer Service (non GraphQL Aware)--> Resolver --> Repository --> DB

Flow-2 --> GQL Reqeust --> API GW with Apollo server --> Resolver ( here resolver retrieves the broker from ctx passed down from Apolloserver in Api GW Service) -->ctx.broker.call (Moleculer Service (non GraphQL Aware))-->Repository --> DB?

Truly appreciate if we can see some samples for this please

@iasbm
Copy link

iasbm commented Jul 22, 2022

@ujwal-setlur and @teezzan we managed to get it working by using "Flow-2" approach as per my message above and I presume you also must have used Flow-2. If by any chance you got it working through Flow-1 then appreciate if you can share some code snippet pls.

@ujwal-setlur
Copy link

@iasbm I am not quite clear on Flow-1, but my implementation is similar to Flow-2:

@Resolver()
export class PingResolver {
  @Query(() => String)
  async Ping(@Ctx() ctx: ResolverContext): Promise<String> {
    const { moleculerBroker } = ctx;
    const response = moleculerBroker.call('authz.ping');
    return response;
  }
}

@iasbm
Copy link

iasbm commented Jul 22, 2022

thanks @ujwal-setlur for confirming this. Your confirmation aligns with our implementation of Flow-2, cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants