Original: https://blog.envoyproxy.io/envoy-and-grpc-web-a-fresh-new-alternative-to-rest-6504ce7eb880


By Luc Perkins


Translator: Li Qi

Grpc-web, as a JavaScript client library for gRPC, enables Web applications to interact directly with gRPC services via Envoy without using a custom HTTP server as an intermediary. After about two years of active development, last week the gRPC team announced on the CNCF blog that the GA version of GRPC-Web was officially released.

I’ve had a personal interest in GRPC-Web ever since READING this post in Improbable Engineering Blog. I had been bullish on gRPC’s performance, extensibility, and IDL (Interface Description Language) driven service interaction, and specifically wanted to remove the REST part of the service invocation chain. I’m happy to have the official release of GRPC-Web, which breaks new ground in the world of Web development.

I think the advantage of GRPC-Web is to build a complete end-to-end gRPC service architecture from the Web side down. Previously, if you wanted the Web side to interact with gRPC services, you had to develop your own REST interface to handle the conversion between HTTP and gRPC. With grPC-Web, instead of having to write additional HTTP interfaces ourselves, we can directly encapsulate all data interfaces with Protocol Buffers (borrowed from Envoy, which I’ll explain in more detail below).

REST mode

The following figure shows two ways to build a Web App based on the gRPC service architecture. On the left is the traditional REST approach. On the right is grPC-Web mode.

As the figure on the left shows, the REST API serves only as a connection point between the Web App and the back-end gRPC service. In most scenarios, REST services simply translate HTTP calls into gRPC calls.

For example, the client needs to validate the service and submits JSON data to the /auth of the HTTP server with a POST request. Then the HTTP end converts the JSON data into the Protobuf AuthRequest message and sends the message to the gRPC authentication service. Finally, it obtains the AuthResponse response from the gRPC service and converts it into JSON data and returns it to the front end. As I said in my CNCF blog post, there is nothing wrong with this approach, it is a solution that many developers use well, and if it satisfies you, you can continue to use it this way.

Better solution: We would do a lot less work if we could remove HTTP mediations (imagine a JavaScript side sending an AuthRequest message directly to the gRPC service and getting an AuthResponse response). This means we don’t have to worry about HTTP status codes, JSON parsing, and the deployment and administration issues that come with the HTTP service itself.

The right half of the figure above is an alternative to using GRPC-Web. Its architecture is clearer, with a protocol running through the entire gRPC service invocation. There is no additional HTTP logic, and all data interfaces are defined in.proto files. The whole process is that the client sends a Protobuf message to the gRPC service and obtains the Protobuf message from the service.

We only need one component to achieve this good result.

Envoy’s role

I must admit that my earlier statement that GRPC-Web calls the gRPC service directly is not entirely correct. Client calls using GRPC-Web still need to be converted to GRPC-friendly calls. Envoy filled that role. Also Envoy is the default service gateway built into grPC-Web.

Envoy use in combination with GRPC-Web is shown below. In the figure, the Web App invokes a gRPC service, which in turn relies on two other gRPC services. Envoy transforms HTTP/1.1 requests into HTTP/2 requests. In fact, the underlying HTTP protocol needs to be converted, but neither the client nor the server needs to worry about the HTTP layer.

Grpc-web is significantly better than REST because it requires developers to create an Envoy and do some basic configuration, rather than creating the transformation layer themselves.

Envoy Sample configuration

 static_resources:
   listeners:
   - name: listener_0
     address:
       socket_address: { address: 0.0. 0. 0. port_value: 8080 }
     filter_chains:
     - filters:
       - name: envoy.http_connection_manager
         config:
           codec_type: auto
           stat_prefix: ingress_http
           route_config:
             name: local_route
             virtual_hosts:
             - name: local_service
               domains: [" * "]
               routes:
               - match:
                   prefix: "/ "route: cluster: auth_service cors: allow_origin: -"*"
                 allow_methods: GET, PUT, DELETE, POST, OPTIONS
                 allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-r esponse-streaming,x-user-agent,x-grpc-web
                 max_age: "1728000"
                 expose_headers: grpc-status,grpc-message
                 enabled: true
           http_filters:
           - name: envoy.grpc_web
           - name: envoy.cors
           - name: envoy.router
   clusters:
   - name: auth_service
     connect_timeout: 0.25s
     type: logical_dns
     http2_protocol_options: {}
     lb_policy: round_robin
     hosts:
 socket_address:
   address: auth-server
   port_value: 9090Copy the code

In general, this is just the basic HTTP configuration Envoy, with a few differences:

  • A few required custom headers for grPC-Web: X-Grpc-web, grPC-Status and grPC-Message (JavaScript handles them automatically)

  • The built-in enlist.grpc_webhttp filter is used to perform complex GRPC-Web proxy work

  • Specify http2_PROTOCOL_options: {} in the auth_service configuration to get HTTP/2 links

You only need to write a bit of YAML configuration to get rid of the extra HTTP adaptation work. You don’t have to worry about method mapping between HTTP and gRPC, you don’t have to go to StackOverflow to figure out which HTTP state code corresponds to which gRPC state code, and you don’t have to wrap Proto messages in JSON.

A new way

Grpc-web + Envoy provides a novel approach to Web development that ensures Protocol Buffers and gRPC type-safety and circumnavigates many common problems in HTTP+REST. I recommend you try it on your next project.