loopbackio / loopback4-extension-grpc

gRPC Extension for LoopBack 4
Other
18 stars 8 forks source link

Auto generate typescript interfaces/classes from proto.file #15

Open VMois opened 7 years ago

VMois commented 7 years ago

Original Description

To eliminate two files definition by users (proto.file and typescript) we can create a tool to automatically generate typescript interfaces/classes from a proto file and add it, for example, to CLI.

Interesting example is this tool -> https://geotho.github.io/protobuf-to-typescript/ But the main problem this tool doesn't handle services and RPC methods.

Maybe we need to create our generating tool based on this? If yes, where to put our tool and how it will work?

Implement auto-generated typescript interfaces and classes from proto files. This should automatically discover and watch proto files.

PR: https://github.com/strongloop/loopback4-extension-grpc/pull/17 https://github.com/strongloop/loopback4-extension-grpc/pull/18 https://github.com/strongloop/loopback4-extension-grpc/pull/22

  1. [X] Autodiscover protofiles within project directory
  2. [X] Generate declaration and service file from proto file
  3. [X] Improve decorator to receive TS gencode
  4. [X] Improve gRPC Server to accept TS gencode
  5. [X] Fix generator output structure
  6. [ ] Watch for proto files changes to generate updated TS Files
jonathan-casarrubias commented 7 years ago

Yeah I tried services and rpc methods and doesnt work, we might contribute on that repo to make services to work, but definitely we need to find a way to successfully generate typescript interfaces from proto files

VMois commented 7 years ago

I tried this tool to generate typescript file from protobuf https://www.npmjs.com/package/ts-protoc-gen . The tool is based on protoc. It does not generate interfaces but classes with lots of methods and I don't know we can use it in our extension. Example output from our test proto file.

greeter_pb_service.ts ->

// package: test
// file: greeter.proto

import * as greeter_pb from "./greeter_pb";
export class Greeter {
  static serviceName = "test.Greeter";
}
export namespace Greeter {
  export class SayHello {
    static readonly methodName = "SayHello";
    static readonly service = Greeter;
    static readonly requestStream = false;
    static readonly responseStream = false;
    static readonly requestType = greeter_pb.HelloRequest;
    static readonly responseType = greeter_pb.HelloReply;
  }
}

greeter_pb.d.ts ->

// package: test
// file: greeter.proto

import * as jspb from "google-protobuf";

export class HelloRequest extends jspb.Message {
  getName(): string;
  setName(value: string): void;

  serializeBinary(): Uint8Array;
  toObject(includeInstance?: boolean): HelloRequest.AsObject;
  static toObject(includeInstance: boolean, msg: HelloRequest): HelloRequest.AsObject;
  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
  static serializeBinaryToWriter(message: HelloRequest, writer: jspb.BinaryWriter): void;
  static deserializeBinary(bytes: Uint8Array): HelloRequest;
  static deserializeBinaryFromReader(message: HelloRequest, reader: jspb.BinaryReader): HelloRequest;
}

export namespace HelloRequest {
  export type AsObject = {
    name: string,
  }
}

export class HelloReply extends jspb.Message {
  getMessage(): string;
  setMessage(value: string): void;

  serializeBinary(): Uint8Array;
  toObject(includeInstance?: boolean): HelloReply.AsObject;
  static toObject(includeInstance: boolean, msg: HelloReply): HelloReply.AsObject;
  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
  static serializeBinaryToWriter(message: HelloReply, writer: jspb.BinaryWriter): void;
  static deserializeBinary(bytes: Uint8Array): HelloReply;
  static deserializeBinaryFromReader(message: HelloReply, reader: jspb.BinaryReader): HelloReply;
}

export namespace HelloReply {
  export type AsObject = {
    message: string,
  }
}

@jonathan-casarrubias In your opinion, do we have a chance to use something like this? I think it's too complicated.

I searched a lot and don't find a tool that can simply generate interfaces from protobuf file. Probably, we need to write our own tool or try to fit others tool in our project.

jonathan-casarrubias commented 7 years ago

@VMois hey this is a good research...

Well I think this has potential, I like the HelloRequest and HelloReply extending the jspb.Message from google-protobuf.

I want to make sure that the sent gRPC message actually contains all of those methods, if so.. I think these will allow us to actually use this library.

The declaration file seems to be fine to me, but the service is kind of odd... Not sure we can use that one

jonathan-casarrubias commented 7 years ago

You know what, after analyzing the generated code I think we actually can implement everything.

I'm unable to work on this today but tomorrow I will try to implement this I have a very good plan for this

jonathan-casarrubias commented 7 years ago

FYI: Updated issue description

VMois commented 6 years ago

@jonathan-casarrubias We can close this issue because you have implemented proto files auto-generation already.