Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gRPC-web protocol wrapper/proxy #73

Open
calvellido opened this issue Nov 3, 2017 · 3 comments
Open

gRPC-web protocol wrapper/proxy #73

calvellido opened this issue Nov 3, 2017 · 3 comments
Labels
enhancement New feature or request help wanted Extra attention is needed question Further information is requested

Comments

@calvellido
Copy link
Contributor

calvellido commented Nov 3, 2017

It just so happens that the gRPC protocol can't be directly used from a browser environment. Not because it doesn't exist a JavaScript implementation, but due to browser limitations. Being the main issue, among other setbacks, the lack of trailer metadata support on browsers / fetch implementations.

grpc/grpc#2786
whatwg/fetch#34 (comment)

With this in mind, the approach taken by Google/gRPC team is to set an analog gRPC spec compatible with web browsers. This is needed until fetch/streams API spec is fully supported on web browsers, which can occur in ~2-3 years, then a browser could speak native gRPC protocol, being based on the JS node implementation.

They specifically indicate in the document that the protocol is designed to make it easy for a proxy to translate between the protocols as this is the most likely deployment model. The published protocol proposal can be consulted here:

https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md

This document is essentially a delta of the differences with the protocol details specified in the official native gRPC wire protocol. Some of these needed changes include (but are not limited to):

  • Specific Content-Type (application/grpc-web, application/grpc-web-text).
  • Support for any HTTP/*, not only HTTP/2.
  • Use of message framing, instead of HTTP/2 transport mapping (probably due to this last point, more on the differences between them here). And with this including the RPC response status as part of the response body, since on native gRPC this status is part of the trailer.
  • Not setting the User-Agent explicitly, letting the browser to do that as expected, and use a custom header (X-User-Agent) that take the user agent native spec user agent role.

The message framing and the trailer considerations look like the meatier parts of this, and it doesn't look like something trivial. The fact that we are moving in a somehow greenfield territory makes it quite a challenge, but if any indication, the Improbable Go wrapper implementation can be used as insight.

The gRPC team also notices that besides the spec, its own implementation of grpc-web was initially developed for Google's own projects (...) and they are yet to go through the process to open-source the code base, but until that moment comes, we can rely on the Improbable spec interpretation, as it's proved to be working.

Another approaches worth to be discussed could be:

Further info and relevant discussions on this topic:

https://improbable.io/games/blog/grpc-web-moving-past-restjson-towards-type-safe-web-apis
grpc/grpc#2786
grpc/grpc-experiments#159
grpc/grpc#8682 (comment)

@calvellido calvellido added enhancement New feature or request help wanted Extra attention is needed question Further information is requested labels Nov 3, 2017
@vejeta
Copy link

vejeta commented Nov 6, 2017

It could be interesting, no matter the final solution, to create a gRPC-web proxy server in Scala, instead of Go.

@juanpedromoreno
Copy link
Member

I'm starting working on this, thanks for such as detailed description @calvellido

@juanpedromoreno juanpedromoreno self-assigned this Nov 6, 2017
@juanpedromoreno
Copy link
Member

juanpedromoreno commented Nov 7, 2017

Initially, this would be an initial approach working together with the frees-rpc:

@service
trait MyService {

  @rpc(Avro)
  @http(GET, "/v1/service/unary")
  def unary(a: Request): FS[Response]

}

The only difference, when defining this protocol would be the @http annotation, which receives two parameters:

  • HTTP method.
  • REST Path where the http service will be available.

The HTTP method type ADT would be:

sealed trait MethodType extends Product with Serializable
case object GET         extends MethodType
case object POST        extends MethodType
case object PUT         extends MethodType
case object DELETE      extends MethodType
case object PATCH       extends MethodType

Ideally, the gateway server would be derived by the scalameta macro, and this service also registered to it automatically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants