Skip to content

Vertispan/grpc-gwt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

grpc-web-gwt

gRPC-web support for GWT/J2CL projects - starts with the basic gRPC APIs and stubs, and provides both replacements for those jars, plus gRPC/gRPC-web Channel implementations.

Generated from the Java projects for grpc-api, grpc-stub, grpc-protobuf, and grpc-protobuf-lite. Makes use of standard OpenRewrite rules and some rules specifically written to simplify projects for GWT.

A future version might split these dependencies into separate jars, but for now a subset of the original classes from all four are included in a single jar.

Implementation differences

To simplify the effort of transforming the implementation, two features have been removed. Both technically could be restored, but at a glance there doesn't seem to be an obvious need.

At present, there is no ASCII charset in GWT, so it is assumed that the server is correctly sending ascii status and metadata values. All valid ascii (e.g. below 128) are equal to their corresponding utf8 value, so there should be no difference in behavior.

BinaryStreamMarshaller has also been effectively removed, along with the Metadata.Key.of() overload that supports it. The current implementation used Class.isInstance to check which marshaller was in use, though if required this could be reimplemented without any reflection at all.

Browser limitations

gRPC is marketed as a "universal" RPC framework that runs in "any environment", but in practice it is entirely unusable in browsers. Instead, gRPC-web offers a few small changes over gRPC to make it mostly compatible with browsers:

  • http/1.1 is supported instead of just h2. In most browsers this limits the number of concurrent streams (usually 6) to a single server, so h2 is still desired for most use cases.
    • Additionally, browsers do not support h2c (h2 over cleartext), so gRPC-web over h2 is limited to TLS connections. This can make localhost or dev/staging deployments difficult to use.
  • Rather than HTTP trailers, a final body payload can be read as if it were an http/1 headers block. This doesn't apply to trailers-only responses
  • The user-agent header cannot be controlled by clients in a browser runtime, so x-user-agent should be used instead.
  • Since all of this adds up to "not actually gRPC", the content-type header should be prefixed with application/grpc-web or application/grpc-web-text.

These limitations are intended to "make it easy for a proxy to translate between the protocols as this is the most likely deployment model." Unfortunately, they only cover a subset of the limitations that browsers impose, so it isn't actually possible to run a proxy which can translate arbitrary gRPC services. The browser's fetch() implementation does not support any client-streaming use cases, which limits clients from participating in either bidirectional streaming or client streaming RPCs. At the time the spec was written it was believed that by 2019 this would be resolved, and was later revised (still with a two-year estimate) to instead be part of the streams spec. While Chrome does now technically support streaming uploads, it is required that this be done in "half duplex" mode, which still prevents bidirectional streams from being useful.

For these reasons, other gRPC clients such as (improbable-eng/grpc-web)[https://github.com/improbable-eng/grpc-web/] have included a websocket transport for gRPC messages. Unfortunately, that repository is no longer maintained, and some features we have found to be necessary were never shipped or never implemented.

A simple fetch() implementation is provided which supports unary and server-streaming calls, but by itself cannot support other streaming calls.

Unfinished transports

This library will include two websocket transports - the first is compatible with improbable-eng/grpc-web using one websocket per stream, and the second supports using a single websocket for multiple streams to the same server (in roughly the same way that http2 would do with streams on a single socket). The first is included for compatibility with any existing proxies that support this feature - we mostly encourage the use of the second where required.

Another implementation will be provided that uses server-streaming fetch() requests to receive messages for a given stream, and a unary fetch() to send messages. These can be paired with a server-side tools to modify a Java BindableService to include pairs of gRPC methods which will be treated by the real server method as a single streaming method. Some implementation details are likely to be left out, specifically around handling the state of pairing up messages etc, and naturally any reverse proxy would be required to forward all calls to the same server to be handled uniformly.

Not a browser?

Technically, a Channel implementation can be written for non-browser clients with better h2 support, and that will be gRPC proper, rather than gRPC-web. Node.js for example has a serviceable h2 implementation that can be used in Electron apps or server side - it additionally supports bidirectional streaming, so a Channel implementation will be easier to provide without any workarounds. At this time, this project does not provide one.

Usage

Add com.vertispan.grpc:grpc-gwt to your project dependencies, replacing io.grpc:grpc-* dependencies. The version will be based on the grpc-java build being used, with an integer suffix to allow for packaging changes. For example, current released versions:

grpc-java grpc-gwt Description
1.63.1 1.63.1-1 Initial release

Replace/exclude any existing grpc-java dependencies with this library. Add an inherits in your project's GWT module:

<inherits name="io.grpc.Grpc" />

Then, generate your own stubs as normal with protoc, taking care to only use the async stubs.

Additionally, one or more io.grpc.Channel implementation should be picked from the provided dependencies, and passed to the newStub(..) method when creating your generated client service.

grpc-web-gwt-fetch

A Channel implementation that uses the browser's fetch() API to make requests. This supports unary and server-streaming calls.

Add com.vertispan.grpc:grpc-web-gwt-fetch to your project dependencies. Then, add an inherits in your project's GWT module:

<inherits name="com.vertispan.grpc.fetch.Fetch" />

Building

This can be built simply with mvn install. The clean goal will remove the generated sources, so when changing rewrite rules or grpc versions, a mvn clean install may be required.

About

Transforms grpc-java to be compatible with GWT

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages