moleculer-apollo-server
moleculer-apollo-server copied to clipboard
Can type-graphql be used with this?
Hey
is there a way i can use this with type-graphql?
https://github.com/19majkel94/type-graphql
I don't think it can in the near feature
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?
@ujwal-setlur mentioned at Discord that he's using TypeGraphQL. Maybe you can ask him
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.
@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.
@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?
@teezzan I'll need to see some code snippets...
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.
@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
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.
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?
Solved... Apollo Server context to the rescue. https://www.apollographql.com/docs/apollo-server/security/authentication/
Thanks
Yep
--ujwal On Nov 15, 2020, 4:16 PM -0800, Yusuf Taiwo Hassan [email protected], wrote:
Solved... Apollo Server context to the rescue. https://www.apollographql.com/docs/apollo-server/security/authentication/ Thanks — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.
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
@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.
@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;
}
}
thanks @ujwal-setlur for confirming this. Your confirmation aligns with our implementation of Flow-2, cheers