protoc-gen-grpc-gateway-ts is a Typescript client generator for the grpc-gateway project. It generates idiomatic Typescript clients that connect the web frontend and golang backend fronted by grpc-gateway.

Overview

protoc-gen-grpc-gateway-ts

protoc-gen-grpc-gateway-ts is a Typescript client generator for the grpc-gateway project. It generates idiomatic Typescript clients that connect the web frontend and golang backend fronted by grpc-gateway.

Features:

  1. idiomatic Typescript clients and messages
  2. Supports both One way and server side streaming gRPC calls
  3. POJO request construction guarded by message type definitions, which is way easier compare to grpc-web
  4. No need to use swagger/open api to generate client code for the web.

Get Started

Install protoc-gen-grpc-gateway-ts

You will need to install protoc-gen-grpc-gateway-ts before it could be picked up by the protoc command. Just run cd protoc-gen-grpc-gateway-ts; go install .

Sample Usage

protoc-gen-grpc-gateway-ts will be used along with the protoc command. A sample invocation looks like the following:

protoc --grpc-gateway-ts_out=ts_import_roots=$(pwd),ts_import_root_aliases=base:. input.proto

As a result the generated file will be input.pb.ts in the same directory.

Parameters:

ts_import_roots

Since a protoc plugin do not get the import path information as what's specified in protoc -I, this parameter gives the plugin the same information to figure out where a specific type is coming from so that it can generate import statement at the top of the generated typescript file. Defaults to $(pwd)

ts_import_root_aliases

If a project has setup alias for their import. This parameter can be used to keep up with the project setup. It will print out alias instead of relative path in the import statement. Default is "".

ts_import_roots & ts_import_root_aliases are useful when you have setup import alias in your project with the project asset bundler, e.g. Webpack.

fetch_module_directory and fetch_module_filename

protoc-gen-grpc-gateway-ts will a shared typescript file with communication functions. These two parameters together will determine where the fetch module file is located. Default to $(pwd)/fetch.pb.ts

use_proto_names

To keep the same convention with grpc-gateway v2 & protojson. The field name in message generated by this library is in lowerCamelCase by default. If you prefer to make it stick the same with what is defined in the proto file, this option needs to be set to true.

logtostderr

Turn Ton logging to stderr. Default to false.

loglevel

Defines the logging levels. Default to info. Valid values are: debug, info, warn, error

Examples:

The following shows how to use the generated typescript code.

Proto file: counter.proto

// file: counter.proto
message Request {
  int32 counter = 1;
}

message Response {
  int32 result = 1;
}

service CounterService {
  rpc Increase(Request) returns (Response);
  rpc Increase10X(Request) returns (stream Response);
}

Run the following command to generate the Typescript client:

protoc --grpc-gateway-ts_out=. counter.proto

Then a counter.pb.ts file will be available at the current directory. You can use it like the following example.

import {CounterService} from './counter.pb'

// increase the given number once  
async function increase(base: number): Promise<number> {
  const resp = await CounterService.Increase({counter: base})
  return resp.result
} 

// increase the base repeatedly and return all results returned back from server
// the notifier after the request will be called once a result comes back from server streaming
async function increaseRepeatedly(base: number): Promise<number[]> {
  let results = []
  await CounterService.Increase10X({base}, (resp: Response) => {
    result.push(resp.result)
  })

  return results
}

##License

Copyright 2020 Square, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • Properly encode Uint8Array fields

    Properly encode Uint8Array fields

    Fixes: https://github.com/grpc-ecosystem/protoc-gen-grpc-gateway-ts/issues/22

    Binary data should be represented as base64 encoded string in the JSON encoded body. Use replacer to return base64 encoded string when Uint8Array type is detected.

    Signed-off-by: Artem Chernyshev [email protected]

    opened by Unix4ever 10
  • Handle rendering of URL Query Parameters in renderURL

    Handle rendering of URL Query Parameters in renderURL

    The following is extracted from this file: http.proto

    // HTTP | gRPC
    // -----|-----
    // `GET /v1/messages/123456`  | `GetMessage(name: "messages/123456")`
    //
    // Any fields in the request message which are not bound by the path template
    // automatically become HTTP query parameters if there is no HTTP request body.
    // For example:
    //
    //     service Messaging {
    //       rpc GetMessage(GetMessageRequest) returns (Message) {
    //         option (google.api.http) = {
    //             get:"/v1/messages/{message_id}"
    //         };
    //       }
    //     }
    //     message GetMessageRequest {
    //       message SubMessage {
    //         string subfield = 1;
    //       }
    //       string message_id = 1; // Mapped to URL path.
    //       int64 revision = 2;    // Mapped to URL query parameter `revision`.
    //       SubMessage sub = 3;    // Mapped to URL query parameter `sub.subfield`.
    //     }
    //
    // This enables a HTTP JSON to RPC mapping as below:
    //
    // HTTP | gRPC
    // -----|-----
    // `GET /v1/messages/123456?revision=2&sub.subfield=foo` |
    // `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield:
    // "foo"))`
    //
    

    However it seems like renderURL function in protoc-gen-grpc-gateway doesn't render the fields in the request message which are not bound by the path template to become URL query parameters if there is no HTTP request body.

    Any advice on how to handle this would be great! Thanks in advance 🙏🏼

    opened by atreya2011 8
  • Handling errors

    Handling errors

    The fetch function seems to ignore the .ok status of the fetch response. This means that if there is a gRPC error, data is returned of the error type instead of the declared response type.

    Shouldn’t the fetch function throw in case of http errors (I.e. if .ok is false), so the client can catch errors? (And so there is no typing inconsistency)

    opened by remko 7
  • Handling well-known types

    Handling well-known types

    Given the following proto message:

    syntax = "proto3";
    
    import "google/protobuf/timestamp.proto";
    import "google/protobuf/any.proto";
    
    message User {
      string                    id       = 1;
      string                    name     = 2;
      google.protobuf.Timestamp my_field = 3;
    }
    
    // https://developers.google.com/protocol-buffers/docs/proto3#any
    message ErrorStatus {
      string   message                     = 1;
      repeated google.protobuf.Any details = 2;
    }
    

    The following TypeScript is being generated which throws a type error because neither timestamp.pb.ts nor any.pb exist.

    /*
    * This file is a generated Typescript file for GRPC Gateway, DO NOT MODIFY
    */
    
    import * as GoogleProtobufAny from "../google/protobuf/any.pb"
    import * as GoogleProtobufTimestamp from "../google/protobuf/timestamp.pb"
    
    export type User = {
      id?: string
      name?: string
      myField?: GoogleProtobufTimestamp.Timestamp
    }
    
    export type ErrorStatus = {
      message?: string
      details?: GoogleProtobufAny.Any[]
    }
    

    Please let me know if I am missing any steps in the generation process 🙏🏼 I used the following command to generate the above TypeScript file.

    protoc -I. --grpc-gateway-ts_out=. --grpc-gateway-ts_opt logtostderr=true --grpc-gateway-ts_opt loglevel=debug ./proto/example.proto

    opened by atreya2011 7
  • Use `import type` for type imports in template

    Use `import type` for type imports in template

    When a proto file has imports, the generator generates code like

    import * as GoogleProtobufTimestamp from "./google/protobuf/timestamp.pb";
    

    The default setup of TypeScript in the bundler I use is strict, and is set up to give errors on type-only imports:

    error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
    

    I can work around this by loosening the tsconfig setting.

    Would it be possible to replace the imports generated for these kinds of import by import type to avoid these TypeScript errors on strict setups?

    opened by remko 6
  • Handle rendering of URL Query Parameters in renderURL

    Handle rendering of URL Query Parameters in renderURL

    Resolves #9

    TODO:

    • [x] Create a TypeScript function in template to build URL query parameters
    • [x] Handle nested message types.
    • [x] Handle primitive repeated fields.
    opened by atreya2011 6
  • Add ts_package extension

    Add ts_package extension

    This PR adds the grpc.gateway.protoc_gen_grpc_gateway_ts.options.ts_package option to specify the package name of proto files.

    For example, we can add following lines to google/protobuf/empty.proto with package name "google-protobuf/google/protobuf/empty_pb". Then we can use @types/google-protobuf package for google.protobuf.Empty.

    import "protoc-gen-grpc-gateway-ts/options/ts_package.proto";
    option (grpc.gateway.protoc_gen_grpc_gateway_ts.options.ts_package) = "package_name";
    

    Related to: protocolbuffers/protobuf-javascript#47

    opened by higebu 4
  • renderURL does not use lowerCamelCase field names

    renderURL does not use lowerCamelCase field names

    Given a proto file with the following annotation and fieldname for GetUserRequest:

    service UserService {
      rpc GetUser(GetUserRequest) returns (GetUserResponse) {
        option (google.api.http) = {
          get: "/api/v1/user/{user_id}"
        };
      }
    }
    
    message GetUserRequest {
      string user_id = 1;
    }
    
    message GetUserResponse {
      User user = 1;
    }
    
    message User {
      string id   = 1;
      string name = 2;
    }
    

    generates the following TypeScript:

    /*
    * This file is a generated Typescript file for GRPC Gateway, DO NOT MODIFY
    */
    
    export type GetUserRequest = {
      userId?: string
    }
    
    export type GetUserResponse = {
      user?: User
    }
    
    export type User = {
      id?: string
      name?: string
    }
    
    export class UserService {
      static GetUser(req: GetUserRequest, initReq?: fm.InitReq): Promise<GetUserResponse> {
        return fm.fetchReq<GetUserRequest, GetUserResponse>(`/api/v1/user/${req["user_id"]}`, {...initReq, method: "GET"})
      }
    }
    

    Which throws a type error because of /api/v1/user/${req["user_id"]} as user_id does not exist in the generated type definition for GetUserRequest

    I have fixed this locally. Is it ok to create a PR?

    opened by atreya2011 4
  • Fix module name and imports

    Fix module name and imports

    I noticed that the module name and imports were not updated to grpc-ecosystem and fixed it in all the appropriate files. Let me know if I have missed anything 🙏🏼

    opened by atreya2011 4
  • Add enable_styling_check option to README

    Add enable_styling_check option to README

    I noticed this option isn't documented in the README, so I went ahead and added a brief description. Let me know if you want more info, but this is exactly what I wanted so seems useful!

    opened by avegancafe 1
  • Send bytes in a message

    Send bytes in a message

    If a protocol has messages that have bytes type, generator outputs them as Uint8Array, which is not properly encoded by simple JSON.stringify call. See: image

    I guess it should be converted to base64 encoded string instead. For that case stringify calls should either contain replacer or Uint8Array should have toJSON definition.

    opened by Unix4ever 1
  • Sending bytes as query param

    Sending bytes as query param

    The fix for Issue #22 works only if the bytes are in the body of the request, not in query parameters. In this case, they're being removed by flattenRequestPayload even though the type generated is Uint8Array.

    Changing the flattenRequestPayload function to below (see the added third if statement) seems to solve the problem. It reuses the replacer function behaviour.

    function flattenRequestPayload<T extends RequestPayload>(
      requestPayload: T,
      path: string = ''
    ): FlattenedRequestPayload {
      return Object.keys(requestPayload).reduce((acc: T, key: string): T => {
        const value = requestPayload[key];
        const newPath = path ? [path, key].join('.') : key;
    
        const isNonEmptyPrimitiveArray =
          Array.isArray(value) &&
          value.every(v => isPrimitive(v)) &&
          value.length > 0;
    
        const isNonZeroValuePrimitive =
          isPrimitive(value) && !isZeroValuePrimitive(value as Primitive);
    
        let objectToMerge = {};
    
        if (isPlainObject(value)) {
          objectToMerge = flattenRequestPayload(value as RequestPayload, newPath);
        } else if (isNonZeroValuePrimitive || isNonEmptyPrimitiveArray) {
          objectToMerge = { [newPath]: value };
        } else if (value && value.constructor === Uint8Array) {
          objectToMerge = { [newPath]: b64Encode(value, 0, value.length) };
        }
    
        return { ...acc, ...objectToMerge };
      }, {} as T) as FlattenedRequestPayload;
    }
    
    opened by kabece 0
  • Support for annotating deprecated fields

    Support for annotating deprecated fields

    If a field is deprecated in the proto definitions, such as

    message MyMessage {
      string field_a = 1;
      string field_b = 2 [deprecated = true];
    }
    

    Would it be possible to add a deprecated annotation to the generated types:

    export type MyMessage = {
      fieldA?: string
      /**
       * @deprecated
       */
      fieldB?: string[]
    }
    

    If it did, the typescript compiler picks this up giving a warning: Screenshot 2022-07-08 at 18 40 35

    This is useful when deprecating an old field (and often moving to a new one) in a large codebase as it gives a visual indication where the old one is used.

    opened by samstradling 0
  • Windows - Back-slashes in generated import statements

    Windows - Back-slashes in generated import statements

    When using this library on Windows you get generated TS with back-slashes instead of forward-slashes in import statements. Obviously, TS is not very happy about it, and it doesn't work unless you replace all the slashes. Here's an example:

    import * as fm from ".\fetch.pb"
    import * as GoogleApiHttpbody from ".\google\api\httpbody.pb"
    import * as GoogleProtobufEmpty from ".\google\protobuf\empty.pb"
    import * as GoogleProtobufTimestamp from ".\google\protobuf\timestamp.pb"
    
    opened by Drabuna 0
  • Generated TS types for google.protobuf.Timestamp do not match grpc-gateway encoding

    Generated TS types for google.protobuf.Timestamp do not match grpc-gateway encoding

    Context

    I am using some messages in my protos tha use the well-known google.protobuf.Timestamp:

    message Timestamp {
      // Represents seconds of UTC time since Unix epoch
      // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
      // 9999-12-31T23:59:59Z inclusive.
      int64 seconds = 1;
    
      // Non-negative fractions of a second at nanosecond resolution. Negative
      // second values with fractions must still have non-negative nanos values
      // that count forward in time. Must be from 0 to 999,999,999
      // inclusive.
      int32 nanos = 2;
    }
    

    Issue

    When using grpc-gateway + grpc-gateway-ts to generate both the Go server and the TS client respectively, the following type is generated:

    export type Timestamp = {
      seconds?: string
      nanos?: number
    }
    

    However, the Go server encodes the timestamp as a string! (checked the received body in the network tab)

    For now, I am manually replacing the generated timestamp.pb.ts for the following:

    export type Timestamp = string
    

    I am not entirely sure if the best solution is to fix the client side or the server side in this case...

    opened by KenxinKun 0
  • Support additional_bindings

    Support additional_bindings

    The parser and generator should add support for methods with additional_bindings, allowing multiple different URLs to access the same gRPC endpoint. The current code only renders code for the outer method, but silently ignores the additional_bindings.

    This is especially useful when you have bindings using different HTTP verbs, like PUT and PATCH, that hit the same gRPC method but may use different verbs, or populate different fields from the URL.

    opened by mbarrien 0
Releases(v1.1.2)
Owner
gRPC Ecosystem
gRPC Ecosystem that complements gRPC
gRPC Ecosystem
A protoc-gen-go wrapper including an RPC stub generator

// Copyright 2013 Google. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE fi

Kyle Lemons 37 Nov 17, 2022
Jezziki-webapp - Discontinued but finished web app utilizing a golang backend and reactjs frontend

jezziki-webapp discontinued but finished web app utilizing a golang backend and

robertgro 0 Feb 12, 2022
inlets-connect is a proxy that supports HTTPS and the CONNECT method

inlets-connect inlets-connect is a proxy that supports HTTPS and the CONNECT method. It can be deployed as a side-car or stand-alone to proxy to a sin

Alex Ellis 23 Nov 7, 2022
A Twirp RPC OpenAPI generator implemented as `protoc` plugin

twirp-openapi-gen A Twirp RPC OpenAPI generator implemented as protoc plugin Currently supports only OpenAPI 2.0 Usage Installing the generator for pr

Albenik's Golang Projects 1 May 26, 2022
Minekube Connect allows you to connect any Minecraft server

Minekube Connect allows you to connect any Minecraft server, whether online mode, public, behind your protected home network or anywhere else in the world, with our highly available, performant and low latency edge proxies network nearest to you.

Minekube 14 Nov 20, 2022
Grpc-gateway-map-null - gRPC Gateway test using nullable values in map

Demonstrate gRPC gateway behavior with nullable values in maps Using grpc-gatewa

null 1 Jan 6, 2022
gRPC Web implementation for Golang and TypeScript

gRPC-Web: Typed Frontend Development gRPC is a modern, HTTP2-based protocol, that provides RPC semantics using the strongly-typed binary data format o

Improbable Engineering 4.1k Nov 26, 2022
Protoc plugin to generate contract tests for gRPC in Go

Deal - Go Introduction WE DO NOT SUPPORT THE SERVER SIDE YET This plugin allows us to write Consumer-Driver Contracts tests! Usage example Proto servi

Faunists 15 Sep 3, 2022
Protoc plugin used to generate go-kit grpc code

protoc-gen-gokit-endpoint protoc plugin used to generate go-kit grpc code 安装 go install github.com/wwbweibo/protoc-gen-gokit-endpoint/cmd/protoc-gen-g

wangweibo 4 Sep 29, 2022
Protoc plugin used to generate go-kit grpc code

protoc-gen-gokit-endpoint protoc plugin used to generate go-kit grpc code 安装 go

wangweibo 4 Sep 29, 2022
The server-pubsub is the main backend of DATAVOC project that manages all the other web-server modules of the same project such as the processor

server-pubsub The server-pubsub is the main backend of DATAVOC project that manages all the other web-server modules of the same project such as the p

null 0 Dec 3, 2021
A Realtime API Gateway used with NATS to build REST, real time, and RPC APIs, where all your clients are synchronized seamlessly.

Realtime API Gateway Synchronize Your Clients Visit Resgate.io for guides, live demos, and resources. Resgate is a Go project implementing a realtime

Resgate.io - Synchronize Your Clients 605 Nov 28, 2022
Kiwi-balancer - A balancer is a gateway between the clients and the server

Task description Imagine a standard client-server relationship, only in our case

Jozef Lami 0 Feb 11, 2022
Proxy that keeps clients active until the backend server is back online

HoneySmoke HoneySmoke is a prototype proxy for testing until it eventually becomes HoneyHive. HoneySmoke will eventually implement a limbo mode that k

Ethan 4 Nov 20, 2021
Fast and idiomatic client-driven REST APIs.

Vulcain is a brand new protocol using HTTP/2 Server Push to create fast and idiomatic client-driven REST APIs. An open source gateway server which you

Kévin Dunglas 3.3k Nov 27, 2022
🎉 An awesome version control tool for protoc and its related plugins.

❤️ PowerProto is actively maintained! Any questions in use can be directly raised issue, I will respond to you as fast as possible. If you think the p

storyicon 163 Nov 27, 2022
pb: a tool for managing protoc builds and dependencies

pb pb is a Protocol Buffers Build tool that manages dependencies and build confi

Dan Enman 3 Nov 20, 2022
A simple FTP protocol with client and server implemented in TypeScript and Golang

websocket-ftp A simple FTP protocol with client and server implemented in TypeScript and Golang. Example (Client) const buffer: Uint8Array = (new Text

LQR471814 0 Apr 14, 2022
Server and client implementation of the grpc go libraries to perform unary, client streaming, server streaming and full duplex RPCs from gRPC go introduction

Description This is an implementation of a gRPC client and server that provides route guidance from gRPC Basics: Go tutorial. It demonstrates how to u

Joram Wambugu 0 Nov 24, 2021