user8987378
user8987378

Reputation: 332

how to use grpc proto type Struct in nest.js

hey i am trying to implement nest js microservice with grpc. it looks impossible to use nestjs microservice with struct type for plain objects.

how can i use compiled protos with nestjs ?

imports: [
  ClientsModule.register([
    {
      name: 'HERO_PACKAGE',
      transport: Transport.GRPC,
      options: {
        package: 'hero',
        protoPath: join(__dirname, 'hero/hero.proto'),
      },
    },
  ]),
];

how can i load the compiled protos. something like https://medium.com/@waynelpu/how-to-pass-plain-javascript-object-with-gprc-94a91906ab1c

Upvotes: 2

Views: 2566

Answers (1)

Vasek - Tom C.
Vasek - Tom C.

Reputation: 241

I'm maybe late but I found an answer.

Imagine you have the following protobuf

// task.proto
syntax = "proto3";

// Area API
package task;

// Imports
import "google/protobuf/struct.proto";
import "google/protobuf/empty.proto";

message Task {
    string name = 1;

    // Any additional metadata required to execute the task
    google.protobuf.Struct params = 2;
}

service TaskService {
   rpc CreateTask(CreateTaskRequest) returns (Task)
}

message CreateTaskRequest {
  string name = 1;

  google.protobuf.Struct params = 2;
}

You will need to add an option in your module to correctly load object

    await app.connectMicroservice<MicroserviceOptions>({
        transport: Transport.GRPC,
        options: {
            package: [ 'task' ],
            protoPath: [ __dirname + '/protos/task.proto' ],
            url: `${host}:${port}`,
            loader: {
                objects: true // This property
            }
        },
    });

And then in the resolver, you will retrieve a structure that his gRPC Struct compliant, you can find more information here.

Now imagine that you execute a rpc call to CreateTask (Postman has a great beta client for example)

{
  "name": "fugiat qui laboris dolore",
  "params": {
    "fields": {
      "foo": {
        "stringValue": "bar"
      },
      "bar": {
        "numberValue": 4
      },
      "baz": {
        "boolValue": false
      }
    }
  }
}

You will correctly retrieve it in your handler

    async createTask(@Payload(new ValidationPipe({ whitelist: true })) req: CreateTaskRequest): Promise<Task> {
        console.log(req.params)
...
}

Result

[Nest] 36410  - 02/09/2022, 3:33:33 PM     LOG [NestMicroservice] Nest microservice successfully started +55ms
[Nest] 36410  - 02/09/2022, 3:33:33 PM     LOG Workflow gRPC service listening on localhost:8000
[Nest] 36410  - 02/09/2022, 3:33:36 PM     LOG Received rpc call to /area.task.TaskService/CreateTask with data: '{"workflowId":"1f5a0501-ce63-437d-b70f-a0ea3c22f0ff","name":"fugiat qui laboris dolore","type":0,"action":0,"nextTask":"Ut mollit","params":{"fields":{"foo":{"stringValue":"bar"},"bar":{"numberValue":4},"baz":{"boolValue":false}}}}'
{
  fields: {
    foo: { stringValue: 'bar' },
    bar: { numberValue: 4 },
    baz: { boolValue: false }
  }
}

The only thing you have to do now is creating a simple function to correctly wrap struct send by your client. You can find more information with a real example on that repository.

Don't hesitate if you need anything else or if you found a better way to do it :D

Upvotes: 3

Related Questions