Cannot import google's proto with @grpc/proto-loader
Asked Answered
R

2

7

I have the following proto:

syntax = "proto3";

import "google/rpc/status.proto";

message Response {   
    google.rpc.Status status = 1;
}

message Request {   
    Type name = 1;
}

service Service {
    rpc SomeMethod (Request) returns (Response);
}

And I am writing a client in node:

    const path = require('path');
    const grpc = require('grpc');
    const protoLoader = require('@grpc/proto-loader');
    const protoFiles = require('google-proto-files');

    const PROTO_PATH = path.join(__dirname, '/proto/myproto.proto');

    const packageDefinition = protoLoader.loadSync(
      PROTO_PATH,
      {
        keepCase: true,
        longs: String,
        enums: String,
        defaults: true,
        oneofs: true,
        includeDirs: [protoFiles('rpc')],
      },
    );

    const proto = grpc.loadPackageDefinition(packageDefinition);
    const client = new proto.Service('localhost:1111', grpc.credentials.createInsecure());

When I run the client, I get the following error: TypeError: proto.Service is not a constructor. I found it's related to the import of status.proto. What is the right way of importing google protos using proto-loader? The server is in Java.

Resurrection answered 12/10, 2018 at 21:1 Comment(0)
C
9

Olga, you cannot use the absolute path in the PROTO_PATH if you are using includeDirs. Apparently you need to put both path, i.e. path to myproto.proto AND path to the google-proto-files into includeDirs and use just file name as PROTO_PATH then it works just fine. See here:

https://github.com/grpc/grpc-node/issues/470

Here is modified code that works. Please note that I also had to replace "Type" with "int32" in the myproto.proto.

const path = require('path');
const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');
const protoFiles = require('google-proto-files');

const PROTO_PATH = 'myproto.proto';

const packageDefinition = protoLoader.loadSync(
  PROTO_PATH,
  {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
    includeDirs: ['node_modules/google-proto-files', 'proto']
    },
  );

const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
const client = new protoDescriptor.Service('localhost:1111',  grpc.credentials.createInsecure());

Hope it helps. :)

Coldblooded answered 16/10, 2018 at 18:24 Comment(4)
Works with absolute paths: const IMPORT_PATH = path.join(__dirname, '/proto'); const GOOGLE_PROTOS = path.join(__dirname, '../node_modules/google-proto-files'); and includeDirs: [GOOGLE_PROTOS, IMPORT_PATH]Resurrection
Yes, but that's what I meant. You cannot use absolute path in the first argument, i.e. main proto file to load if you also specify includeDirs parameter. As for the includeDirs elements themselves, you can use either relative path(s) or absolute one(s) as you please. This should be documented in the loadSync() caveats or implementation details section, IMHO.Coldblooded
Didn't work with relative paths in insludeDirs, only with absolute ones.Resurrection
I am the maintainer of that package. This constraint is not documented because it is actually a bug in how includeDirs is handled. As for relative includeDirs paths, I would recommend against using them because the paths may not be relative to what you expect them to be relative to.Countersignature
C
0

The problem here is that the path that protoFiles('rpc') returns doesn't work with the import line in your .proto file. That import line means that @grpc/proto-loader is looking for an include directory that contains google/rpc/status.proto, but protoFiles('rpc') returns a directory that directly contains status.proto. So, you have to change one or both of those things so that the relative directories match up properly.

Countersignature answered 15/10, 2018 at 15:58 Comment(3)
Changed to const IMPORT_PATH = path.join(__dirname, '/../node-modules/google-proto-files'); and includeDirs: [IMPORT_PATH], but get the same error - Service is not a constructor.Resurrection
OK, I have been able to confirm that there is some other issue here. I am still fairly confident that that the issue I mentioned is part of the problem.Countersignature
I know the issue is with the import, because I could successfully create the client without using status.proto (commented it out), but I can't find anywhere how to correctly load google protos.Resurrection

© 2022 - 2024 — McMap. All rights reserved.