nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
67.29k stars 7.59k forks source link

[Question about Nestjs+GraphQL+Grpc]NestJS acts as the React GraphQL server and the GRPC client #6924

Closed LbhFront-end closed 3 years ago

LbhFront-end commented 3 years ago

Below is my code. My question is is this architecture feasible and how to modify it to be effective。

[Nest] 23752   - 2021/04/19 下午2:05:27   [InstanceLoader] GraphQLModule dependencies initialized +0ms
[Nest] 23752   - 2021/04/19 下午2:05:27   [NestMicroservice] Nest microservice successfully started +3ms
Method handler FindOne for /hero.HeroService/FindOne expected but not provided
Method handler FindMany for /hero.HeroService/FindMany expected but not provided
[Nest] 23752   - 2021/04/19 下午2:05:27   [NestApplication] Nest application successfully started +499ms
Application is running on: http://[::1]:3000

When i request /graphql

Application is running on: http://[::1]:3000
[Nest] 23752   - 2021/04/19 下午2:19:18   [ExceptionsHandler] 12 UNIMPLEMENTED: The server does not implement this method +830291ms
Error: 12 UNIMPLEMENTED: The server does not implement this method
    at Object.exports.createStatusError (D:\gitlab\nest-grcp-client\node_modules\grpc\src\common.js:91:15)
    at ClientDuplexStream._emitStatusIfDone (D:\gitlab\nest-grcp-client\node_modules\grpc\src\client.js:233:26)
    at ClientDuplexStream._receiveStatus (D:\gitlab\nest-grcp-client\node_modules\grpc\src\client.js:211:8)
    at Object.onReceiveStatus (D:\gitlab\nest-grcp-client\node_modules\grpc\src\client_interceptors.js:1311:15)
    at InterceptingListener._callNext (D:\gitlab\nest-grcp-client\node_modules\grpc\src\client_interceptors.js:568:42)
    at InterceptingListener.onReceiveStatus (D:\gitlab\nest-grcp-client\node_modules\grpc\src\client_interceptors.js:618:8)
    at D:\gitlab\nest-grcp-client\node_modules\grpc\src\client_interceptors.js:1127:18

image

hero/hero.proto

syntax = "proto3";

package hero;

service HeroService{
    rpc FindOne (HeroById) returns (Hero);
    rpc FindMany (stream HeroById) returns (stream Hero);
}

message HeroById{
    int32 id = 1;
}

message Hero{
    int32 id = 1;
    string name = 2;
}

hero/models/hero.model.ts


import { Field, ObjectType, ID } from '@nestjs/graphql';

@ObjectType()
export class HeroModel {
    @Field(() => ID)
    id: string;

    @Field({ nullable: true })
    name: string;
}

hero/interfaces/hero.interface.ts

import { Observable } from 'rxjs';

export interface Hero {
  id: number;
  name: string;
}

export interface HeroById {
  id: number;
}

export interface IHeroService {
  findOne(data: HeroById): Observable<Hero>;
  findMany(upstream: Observable<HeroById>): Observable<Hero>;
}

hero/hero.service.ts

import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { Observable, ReplaySubject } from 'rxjs';
import { toArray } from 'rxjs/operators';
import { Hero, HeroById, IHeroService } from './interfaces/hero.interface';

@Injectable()
export class HeroService implements OnModuleInit {
    private heroService: IHeroService;
    constructor(@Inject('HERO_PACKAGE') private readonly client: ClientGrpc) { }

    onModuleInit() {
        this.heroService = this.client.getService<IHeroService>('HeroService');
    }

    fetch(): Observable<Hero[]> {
        const ids$ = new ReplaySubject<HeroById>();
        ids$.next({ id: 1 });
        ids$.next({ id: 2 });
        ids$.complete();

        const stream = this.heroService.findMany(ids$.asObservable());
        return stream.pipe(toArray());
    }

    fetchOne(id: string): Observable<Hero> {
        return this.heroService.findOne({ id: +id })
    }
}

hero/hero.resolver.ts

import { Args, Query, Resolver } from '@nestjs/graphql';
import { HeroService } from './hero.service';
import { HeroModel } from './models/hero.model';

@Resolver(of => HeroModel)
export class HeroResolver {
    constructor(private heroService: HeroService) { }

    @Query(returns => [HeroModel])
    async heros() {
        return await this.heroService.fetch();
    }

    @Query(returns => HeroModel)
    async hero(@Args('id') id: string) {
        return await this.heroService.fetchOne(id)
    }
}

hero/module.ts

import { HeroService } from './hero.service';
; import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { grpcClientOptions } from 'src/grpc-client.options';
import { HeroResolver } from './hero.resolver';

@Module({
    imports: [
        ClientsModule.register([
            {
                name: 'HERO_PACKAGE',
                ...grpcClientOptions
            }
        ])
    ],
    controllers: [],
    providers: [HeroResolver, HeroService],
    exports: [HeroService]
})
export class HeroModule { }

grpc-client.options.ts

import { ClientOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';

export const grpcClientOptions: ClientOptions = {
    transport: Transport.GRPC,
    options: {
        url:'localhost:4500',
        package: 'hero',
        protoPath: join(__dirname, './hero/hero.proto')
    }
}

main.ts

import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions } from '@nestjs/microservices';
import { grpcClientOptions } from './grpc-client.options';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.connectMicroservice<MicroserviceOptions>(grpcClientOptions);

  await app.startAllMicroservicesAsync();
  await app.listen(3000);
  console.log(`Application is running on: ${await app.getUrl()}`)
}
bootstrap();

Need Help!!!

kamilmysliwiec commented 3 years ago

Please, use our Discord channel (support) for such questions. We are using GitHub to track bugs, feature requests, and potential improvements.