1

I'm trying to build microservice with NestJS and gRPC. It has two services, the first one is the gRPC service, and the second one is the REST service that call gRPC service.

At first, it works fine on unary call, the findRepoById rpc. But it doesn't work on server streaming call, findAllRepos rpc. It throws error like this when i tried to call findAllRepos rpc

UnhandledPromiseRejectionWarning: Error: 12 UNIMPLEMENTED: The server does not implement the method findAllRepos

I wrote the files as shown below

// main.proto

syntax = "proto3";

import "google/protobuf/timestamp.proto";

package main;

enum Visibility {
  PUBLIC = 0;
  PRIVATE = 1;
}

message Repository {
  int32 id = 1;
  string title = 2;
  Visibility visibility = 3;
  google.protobuf.Timestamp lastSeen = 4;
}

service MainService {
  rpc findRepoById (RepoById) returns (Repository) {}
  rpc findAllRepos (NoParam) returns (stream Repository) {}
}

message RepoById {
  int32 id = 1;
}

message NoParam {}
// server.controller.ts

@Controller('repo')
export class RepoController {
  constructor(
    @Inject('RepoService') private readonly repoService: RepoService
  ) {}

  @GrpcMethod('MainService', 'findRepoById')
  findRepoById(request: RepoById, metadata: Metadata): Repository {
    const targetId = request.id;
    return this.repoService.findRepoById(targetId);
  }

  @GrpcStreamMethod('MainService', 'findAllRepos')
  findAllRepos(request: NoParam, metadata: Metadata): Observable<Repository> {
    const subject = new Subject<Repository>();

    const repositories = this.repoService.findAllRepos();
    repositories.map((repo) => {
      subject.next(repo);
    });
    subject.complete();

    return subject.asObservable();
  }
}
// client.service.ts

export class RepoGrpcService implements OnModuleInit {
  private mainService: MainServiceClient;

  constructor(@Inject('main_package') private client: ClientGrpc) {}

  onModuleInit() {
    this.mainService = this.client.getService<MainServiceClient>('MainService');
  }

  findRepoById(id: number): Observable<Repository> {
    return this.mainService.findRepoById({ id });
  }

  @GrpcStreamCall('MainService')
  findAllRepos(): Observable<Repository[]> {
    const results: Repository[] = [];

    const repoStream = this.mainService.findAllRepos({});
    repoStream.forEach((value) => console.log(value));
    repoStream.subscribe({
      next: (repo) => {
        results.push(repo);
      }
    });

    const subject = new Subject<Repository[]>();
    subject.next(results);
    subject.complete();

    return subject.asObservable();
  }
}

I think I already followed all the code same as on NestJS gRPC documentation But somehow it still doesn't work. Is there something wrong I do?

fahmiduldul
  • 924
  • 7
  • 18

4 Answers4

1

as some people have suggested, you should use the @GrpcMethod decorator instead of @GrpcStreamMethod,

but you are also returning an Observable of type Repository[], which looks suspect to me, I think that if what you want to do is return a stream from an array, with returning Observable of type Repository is enough,

finally watching [RxJS documentation][1] on Observables I came up with an effective and simpler approach.

Your approach

@GrpcMethod('MainService')
  findAllRepos(): Observable<Repository[]> {
    const results: Repository[] = [];

    const repoStream = this.mainService.findAllRepos({});
    repoStream.forEach((value) => console.log(value));
    repoStream.subscribe({
      next: (repo) => {
        results.push(repo);
      }
    });

const subject = new Subject<Repository[]>();
subject.next(results);
subject.complete();

return subject.asObservable();   }

My approach

  @GrpcMethod('MainService')
  findAllRepos(): Observable<Repository> {
    const results: Repository[] = [];

    const repoStream = this.mainService.findAllRepos({});
    
    const observable = new Observable<Repositoy>((subscriber)=>{
      repoStream.map((value)=>{
        subscriber.next(value);
      });
    });
    
    return observable;
  
  }

I hope that this helps someone, I've struggled to find grpc server streaming examples on nestjs, and their main doc site only shows examples of unary calls and bidirectional streaming.

Miguel
  • 11
  • 1
  • I've followed different tutorials on using gRPC with NestJs, but nothing is working, my main.ts is ok, and I've added the Controller to the app modules, but I still have the same issue Unimplemented. Maybe someone can share a working example, server and client, please ? – kato2 Mar 28 '23 at 17:02
0

I know it's been a long time since this question was asked, but maybe this answer will help others. Please Attention to documentation, some parts of the code are not mentioned because of previous chapters, So NestJS is not an Exception. It seems, that your problem comes from the controller-module relation Take a look at the documentation again and be sure that your controller is defined in the correct module and your module relations(import) are fine.

NestJs Doc-Module

Official Example

Emir
  • 23
  • 1
  • 5
0

From my experience if it's server side streaming, the @GrpcMethod annotation works.
The document doesn't describe this bit clearly enough, but to me it sounds like only mutual stream services needs GrpcStreamMethod.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
James Jiang
  • 2,073
  • 6
  • 19
  • 25
  • Hi James Jiang. please review my edit, the purpose of which is to turn the impression of asking a clarification question into an obvious answer closer to [answer]. If I broke the purpose of your post feel free to improve - and please accept my apology. – Yunnosch Sep 05 '22 at 14:20
0

To return a server side stream in NestJS, replace the @GrpcStreamMethod decorator with the @GrpcMethod decorator (as used in your findRepoById method).

The @GrpcStreamMethod decorator only works for duplex streaming.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 29 '22 at 10:04