Hacker News new | past | comments | ask | show | jobs | submit login
gRPC-Web is going GA (cncf.io)
345 points by biggestlou on Oct 24, 2018 | hide | past | favorite | 137 comments



I'm still not sold on gRPC vs JSON/REST.

.proto offers me little over a decent development environment around JSON, and it seems to be pretty Google-specific.

I'm also wary of adopting standards that come out of Google.


disclaimer: I work for the gRPC team.

gRPC lets you use other data exchange formats or IDLs as well, such as flatbuffers. However, the protobuf codegen experience we have spent most of the time and energy on.

I see two sides to this - on one hand, there are folks who want a 'contract first' development experience, in which the service contracts are defined first, and the business logic is implemented later. gRPC lends itself to this model very well. Admittedly, this is also the way services are developed in Google.

On the other hand, there are folks who want a model whereby you evolve a service and generate the specs from that service. Currently, this is not the experience that gRPC is optimized for. Time and effort are the main barriers to making this work well alongside a contract-first experience. FWIW: I believe both models have merit and it really depends on what you want to adopt as the source of truth for how your services interact. Ideally, gRPC would be good at both.


IMO json+REST works just as well for contract first workflows. Just write up the contract in an IDL, have both sides agree on it up front, then use codegen tools to generate client SDK(s) for your client language(s) of choice. Same workflow as as with gRPC, though you’re probably less likely to get generated server stubs (which you don’t really need with json+REST anyways).


Could you recommend any codegen tools that generate bindings in Typescript or Go? I suppose there's some tools around swagger and various GraphQL libraries, but I'm not seeing any great options though a quick google search.


I have made negative experience with using a custom swagger-codegen [0] template - the library is quite diffuse with no clear direction in which PRs are merged and which aren't, making it a mess to read and extend. I have however, managed to generate the exact Typescript bindings I wanted using it.

In contrast, I have been using NSwag [1] to generate C# client code with far greater comfort, and it seems to support multiple Typescript clients already.

[0] https://github.com/swagger-api/swagger-codegen [1] https://github.com/RSuter/NSwag


Sorry to hear your negative experience with Swagger Codegen regarding the PRs. Having been "managing" the project for a few years, I agree with you that I've not done a very good job in reviewing and merging all the PRs (239 open PRs as of today) contributed by the awesome community.

Myself and 40+ top contributors have decided to fork Swagger Codegen so as to maintain a community-driven version called OpenAPI Generator [1] with a better governance structure to move the project forward. Now there are 10+ core team members and contributors with proper rights to merge PRs so I think we've better PR management in OpenAPI Generator. Please refer to the Q&A [2] for the reasons behind the fork.

For TypeScript generators, we've recently added the TypeScript Axios client generator [3] and there's an ongoing project to consolidate the TypeScript generators into one [4]. Please check these out and let us know if you've any feedback.

We hope you will find OpenAPI Generator useful in your projects.

[1] https://openapi-generator.tech [2] https://github.com/OpenAPITools/openapi-generator/blob/maste... [3] https://twitter.com/oas_generator/status/1041939441109983232 [4] https://github.com/OpenAPITools/openapi-generator/projects/4


Switched to NSwag here, too. I'm in a Python environment and we use it to generate the TypeScript code for our services.


which IDL do you use? which codegen tools and for which languages?

also i think i'm missing something:

>which you don’t really need with json+REST anyways

why don't you need server stubs for json+REST?


What's the difference between CORBA and Protobuf with regard to IDL? I remember it was supposed to be the next big thing before SOA and webservices took over - I wonder what's different this time?


>CORBA defines commonly needed services such as transactions and security, events, time, and other domain-specific interface models.


Is there a possibility to make the gRPC contracts more universal, to play nicely with things like SignalR, websockets, etc. ?


If you want RPC and PUB/SUB over Websocket, you have the "Web Application Messaging Protocol" standard, which has implementations for Python, JS (node and in browser), PHP, C# and Java.

Checkout the main router, it's open source and handles a decent 6k msg/sec on a raspi: https://crossbar.io/

The best things about it is that you don't have to write the message schemas in advance, only the function signatures.


Thanks a lot, I'm a bit worried about performance here, I wonder how does it compare against standard REST and SignalR in terms of number of active connections, performance, etc.


The general rule of thumbs is that Websocket are cheaper if you want long connection with states to maintain (you only need to identify once) or have a lot of small messages.

However, you have a low number of requests, or big requests, REST is going to be faster.

But as usual, it depends of your implementation and your constraint. After all, facebook is using polling if I recall.


Looks interesting. How does this compare to RabbitMQ or MQTT?


It's a bit more performant than MQTT, but it eats more ressources (bandwidth and cpu). It's still practical for IoT (although I use it for the Web), as the C++ implementation (https://github.com/crossbario/autobahn-cpp) targets embeded systems. However, it uses boost, so it won't fit in extrems memory requirements.

All it all, if your configuration allows it, it's way, way easier and more flexible than MQTT to use.

Combared to RabbitMQ, it's not as fast. You can't beat years of optimized Erlang and field testing by fortune 500. Yet, Rabbit MQ is very low level: you need to setup queues, and consumers, and if you need RPC with returned value you will add manual logic on top of it. Don't get me started if you want to load balance consummers. Real life AMQP is hard.

Comparatively crossbar offers a great out of the box experience.

All in all, I'd say the sweet spot for the tech is between the arduino/raspi and an average website/company micro service archi. If you have very small hardware, MQTT could fit in the tiny space, and if you have a 100 message highways interconnecting your data centers around the world, you may want AMQP. Between those, crossbar.io is great.


> .proto offers me little over a decent development environment around JSON

If your development environment includes Swagger, programmatically generated HTTP clients and servers in multiple languages, built-in intelligent error handling, client-side and server-side type-checking of API requests and responses, gzipping your JSON over the wire, and if you exclusively write in languages like Python and JavaScript where protobuf doesn't serialize and deserialize any faster than JSON, then your development environment is honestly rather exceptional.


don't forget that gRPC multiplexes requests to various RPCs over an existing HTTP2 connection.


Well, most languages do that as "standard" (i.e Go net/http package) including the browsers(chrome, mozilla etc).


Is serialization/deserialization often a service bottleneck?


"""

When using Protobuf on a non-compressed environment, the requests took 78% less time than the JSON requests. This shows that the binary format performed almost 5 times faster than the text format. And, when issuing these requests on a compressed environment, the difference was even bigger. Protobuf performed 6 times faster, taking only 25ms to handle requests that took 150ms on a JSON format.

"""

https://auth0.com/blog/beating-json-performance-with-protobu...


I suggest anyone who reads this comment read the linked article carefully. The difference is in a java-to-java scenario, and the specific task is retrieving 50k structured records.

If your data to be transported is heterogeneous, or one of your endpoints is JavaScript, or if your requests are gates by something else, e.g. bandwidth, transport latency, endpoint raw compute, or human interaction, this dramatic difference may not necessarily apply.


Indeed.

50K records in a single request is a highly abnormal situation, and we're still talking about only shaving 125ms off of the sum total time of that request. In most apps where something that crazy is happening, this is not a problem, as it's clearly in async batch territory.

In a realistic architecture where you need request/response, there's going to be a lot of network calls and database calls. In my experience, it's those DB calls where the largest opportunity to optimize is. The other opportunity is removing N+1 request patterns. A lot of these "Proto is faster than JSON" benchmarks are showing a throughput bottlenecked app, when most apps that need a fast response are concerned with latency, and serialization is often only a few percent of that.


> and serialization is often only a few percent of that

A few percent is a huge performance win. For example shaving 5% off the latency of twitter / facebook's apis is huge. Thing about the compute, energy and bottom line impacts.

I do agree for many protobuf is overkill, there's way lower hanging fruit that will give a greater latency reduction.


Here would be my honest response to that: are you building a Facebook/Twitter scale app?

I've watched quite a few companies waste a lot of time with static IDL systems for performance reasons (going back to CORBA in the 90s) and have had the exact opposite effect.

Facebook has Thrift internally but ultimately ended up building GraphQL because orchestration and parallelism was the limiting factor (they also need a giant amount of coordination glue code to map from Thrift to JSON anyways). Netflix had similar problems which resulted in them building Falcor.

gRPC-web, as well, needs this serialization hop step, so depending on your use case, it may actually be slower. The last two companies I've worked at were in the 50-300 services range with 50K+ business customers and in the 10M+ B2C consumer usage range, and in both cases the IDL translation case (gRPC in one and Thrift in the other) was slower than JSON for many of their applications. Not all cases mind you, but it was definitely hit or miss.

In regards to utilization as well, will the reduced overhead of server CPU utilization for protobuf return a higher ROI than the added engineering time of the solution vs something like Swagger codegen? Will the engineers' extra energy expenditure for their work ever make up for the (potentially) reduced servers? These are serious questions and I think a lot of companies waste a lot of effort and resources by not answering those questions honestly.


The performance advantages of a binary wire format are frankly just the cherry on top. The primary benefits of something like gRPC lie in having a programmatically consumable API spec that can turn your service calls into strongly typed RPC’s, and that benefit is a net gain in engineering productivity rather than a net loss.

You can get much of the same benefit with swagger codegen, though. It’s just that by the time you’re doing that, gRPC wouldn’t be that much more work anyway.

Incidentally, the dividing line between where programming languages are faster at handling protobuf than JSON, namely the dividing line between interpreted and compiled languages, is also the same one where you start to care about performance in the first place. And in Java or Golang, I’m not sure that gRPC is any more difficult.


Is swagger codegen a ton of work? I wrote a swagger codegen library for elixir (by hand) and that took a few weeks, but setting it up is basically three lines of code and a single mix command. Anyone else could use my library and be up and running in a hot second.


How often is often? It becomes more of an issue when you have more microservices because you might have multiple serialization/deserialization steps if you're calling a service that calls a service that calls a service, or if you're managing larger payloads.


This is all provided by Swagger/OpenAPI out of the box. What is exceptional about it?


Swagger Codegen, at least--which, yeah, solves many of the same problems as gRPC, assuming that it supports the server framework you want to use.


err... what server framework isn't supported? and how likely is it to be supported by gRPC? The list of supported languages and frameworks in Swagger Codegen is huge.


In my particular case, I want to use aiohttp on Python, which swagger codegen supports client generation for but not yet server generation (but see https://github.com/swagger-api/swagger-codegen/issues/7451).

Admittedly, gRPC doesn't support asyncio either (https://github.com/grpc/grpc/issues/6046), but gRPC has its own server frameworks already, and is not as well suited for the kinds of applications where you'd want a Python server anyway. But Swagger Codegen is.


We've made some enhancements [1](e.g. OpenAPI 3.0 support) to the Python Flask generator in OpenAPI Generator. For aiohttp support in the Python Flask generator, I don't think anyone is working on that. Please let us know if you've time to make the contribution by opening an issue to start with and we can work with you to make it happen.

(OpenAPI Generator is a fork of Swagger Codegen. For the reasons behind the fork, please refer to the Q&A [2])

[1] https://github.com/OpenAPITools/openapi-generator/pulls?q=is...

[2] https://github.com/OpenAPITools/openapi-generator/blob/maste...


As far as I know, aiohttp is an alternative to Flask, unless there are newer versions of Flask that somehow integrate it.


Thanks for the clarification. You're right. I've created https://github.com/OpenAPITools/openapi-generator/issues/132... for tracking.


I've decided to go this way for now, at least for CRUD APIs:

     Frontend
        |
        | GraphQL
        |
        V
     Backend
        |
        | gRPC
        |
        V
   Microservice
The situation with gRPC in the browser right now isn't ideal. Moreover, the client-side story -- interaction with React/Redux, client-side catching and prefetching, relationships and so on -- is nearly non-existent.

GraphQL is better suited to how JS web apps work. In particular, GraphQL is designed to work with arbitrarily nested graphs of objects at dynamic levels of detail, in a way that makes caching, prefetching and so on fairly simple. And it speaks JSON fluently. gRPC's payloads are fixed, and if you want levels of detail ("fetch posts with creator"; "fetch posts without creator") you have to invent your own scheme for expressing this.

gRPC also isn't particularly developer-friendly when it comes to implementing the client or the server. As with any language-agnostic RPC layer, the interfaces tend to be quite sharp-edged: For example, it's relatively awkward to write services that deal with heterogenous collections of objects ("oneof" fields are limited), and arbitrary structured — as opposed to schema-based that can be expressed with the Proto IDL — data (while there's the "well-known" type Value that can effectively express JSON data, it's easier just to wrap JSON in a proto string).

GraphQL is much smoother to implement the client. Less so for the server, but it's all about graphs of objects, so it has the benefit that every server is essentially implemented the same way (the "verbs" are the same).

GraphQL's introspection story is also better. gRPC has facilities for probing an API without having the schema at hand, but GraphQL arguably has better tools here for now.


> GraphQL is better suited to how JS web apps work.

If the server side is also JS, because it is just a pain in anything else.

I am yet to see a good reason to move away from the flexibility, and most relevant, the tooling of REST.


A few months ago I'd have agreed with you. However, I've recently created a couple of PoCs that changed my mind. The trick however, is to ignore how a lot of people seem to use GraphQL. Just treat it as another view layer that happens to come with schemas. Keep it as far away from your data layer as you can and it's a lot like working with regular old json and rest, with the added benefit of being able to request data in a more flexible manner.


I've built a simple GraphQL server in Clojure using the Lacinia (https://github.com/walmartlabs/lacinia) library. It is about as nice as Apollo to be honest, but you would obviously need to know your way around Clojure.

Lacinia tries to be feature complete (as defined by Apollo Server and GraphQL spec), but obviously does not support everything Apollo does (remote schemas and graphql endpoints for example).

I have not tried any GraphQL server libraries in other languages, so I can't speak for people using C#, Java, or some other language.

I think the tooling around GraphQL is quickly approaching a point where it is better to use GraphQL then REST for client facing services. The fact that you can more precisely define your data needs and don't have to fetch the world, or make multiple round trips, is a big win. The contract a GraphQL schema provides both during development and runtime is also nice.


Say "farewell" to Swagger, etc. and just generate your server & client libraries. I've found it to be far superior to JSON/REST, especially for microservices. Browser support was always the sticking point to wide adoption, so this is great news.


Pretty much every large well known tech company uses an IDL and binary format to exchange data between their very large number of services, so that says something about why this might be a critical piece of the puzzle over have ad-hoc interfaces and shoving JSON everywhere. JSON isn't a very efficient format to send and store data in, and it's a terrible IDL.


It allows you to define an interface wherein you can then simply generate clients and service libraries from that are typesafe.


If most of your communication is between two containers sitting inside a Kubernetes cluster then using GRPC is a no brainer as you get fast performance backed by a strongly typed interface definition language. No human is going to be looking at the traffic so using a binary format makes total sense.

In my experience it's also faster to develop GRPC microservices as you spend less time dealing with Serialization and Deserialization. The only main downsides are the quirks of Protobuf but they are pretty easy to get used to.

Combining with GraphQL you can get a pretty high performance microservice stack, especially if you develop your microservices in Go and use a GraphQL Gateway like Apollo to stitch the whole thing together.


gRPC is more than just a data protocol to me.

Imagine writing JSON/Rest, you have to define end point/router, convert/encode data into JSON/text.

With gRPC, all are done for you, the data is ready and pass to your function handler directly without you writing any glue code.


It's worth keeping in mind too that Protobuf isn't tied to gRPC. Conceptually simpler RPC libraries can exist. Twirp is a good example of this, imo


I used to like .proto, but I found this article recently and it made me reconsider: http://reasonablypolymorphic.com/blog/protos-are-wrong/index...


You should really read the hacker news comments on that rather one-sided view of the topic.

https://news.ycombinator.com/item?id=18188519


Can someone describe why gRPC-Web needs a proxy?

I recently had trouble deciding between the official gRPC-Web and Improbable's gRPC-Web[1]. In the end I decided on Improbable's, because it seemed to not require a proxy. In practice, it's working very nicely.

Yet, I'm still not clear on what exactly the Proxy serves to do, in either case. If a browser supports HTTP 2, why is a proxy needed?

[1]: https://github.com/improbable-eng/grpc-web


gRPC needs access HTTP/2 trailers, which is not supported in browsers today. This necessitates translation in a proxy of some form. It is possible to support in-process or local proxies, but instead starting with this in n languages, we are starting with a proxy, with the intention to build in-process support on languages or use cases where there is real need for it.


I never understood why gRPC decided to use HTTP2 instead of WebSockets. WebSockets is a much simpler protocol and is the closest you can get to raw TCP sockets in the browser.

HTTP was designed for file downloads and uploads while. WebSockets was designed for raw data.


Note that trailers have existed since HTTP 1.1.


The answer--as I recall--from the Chromium team was that they see trailers access as a security issue. HTTP/2 multiplexes many connections and it was a security risk, they said, to allow one client process to access trailers for connections that may be used by different processes or even entirely different sites behind the same load balancer/reverse proxy/etc.

What I don't understand is why gRPC was designed to depend on trailers. Web gRPC is the killer app for this technology. If they could build a new version of the protocol that doesn't rely on trailers, I would be thrilled.


I believe trailers are because you could start streaming a response and end up having an error than you need to communicate out of band. Hopefully someone has a better answer though.


I've been trying to read the HTTP2 spec and I can't figure out whether it's allowable to return or modify the HTTP(2) status code in a trailer instead of in the header.

After some re-readings, I decided it wasn't allowed.

But then, gRPC definitely needs to be able to signal an error even after it has already streamed data. So gRPC would need to use some end-of-connection message, like a trailer.


Yeah, but a lot of software does not support them, at all levels in the chain. Which is a tragedy. They'd be useful in more contexts than just gRPC.


improbable/grpc-web does require a proxy, it just happens to also support a drop-in http proxy in the same app when you're writing a golang based grpc app.

grpc/grpc-web intends to support the same: https://github.com/grpc/grpc-web/blob/master/ROADMAP.md#loca...


Ah hah! Thanks! Yea the drop-in web server works awesomely. It's been a surprisingly painless experience. Thanks for linking the roadmap!


Conceptually, I think you're right -- to serve gRPC requests only requires http2 as a transport and more shouldn't be necessary (edit: I stand corrected, seems like not all HTTP2 features are supported by all modern browsers). In practice, I believe the official gRPC web setup it serves as a translation layer and provides some monitoring bells and whistles. E.g. the official gRPC-Web implementation allows for a base-64 encoded wire format in addition to the typical protobuf binary format, so without a proxy layer, you'd need to define middleware server-side that translates the base64 encoding to the protobuf format.

I think the full set of differences can be found here: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md


HTTP/2 is only necessary if you want to stream, most of gRPC can be implemented over traditional request/response cycles.


Technically it's not even required for that. HTTP/1.1 bodies can be streamed just fine. The main reason not to do this in a browser is that one real TCP connection would be required for each stream, and the number of concurrent outgoing connections from a website is strictly limited. With HTTP/2 this problem goes away.


Can people share their experience and success stories with gRPC and/or GraphQL?

I've tried both in the past and found that APIs are rarely as static as typed API systems require. Many APIs have fields that are required conditionally based on the value of other fields. Other times the schema is dynamic and workarounds are required like stuffing things into a JSON object and making it a "string" in the API. This added a bunch of work to marshall it in and out of a custom workaround format.

In both cases (gRPC and GraphQL) we've run into so many issues that the technology was abandoned and we fell back to plain JSON REST.


We've been using gRPC since late 2015 for communication between IOT devices and cloud hosted servers. We chose gRPC for the following reasons: bi-directional streaming support; TCP connection multiplexing; mutual authentication with client TLS certs; a large company backing it so that it would likely continue to be supported in the future.

In other words gRPC fit our use case nicely and if it didn't exist at the time we would have built our own crappy protocol ourselves.

I think gRPC is great for server-to-server communication and use cases where you need bi-directional streaming. I would not use it for an externally facing API. I would not recommend it for browser-to-server communication unless you are already using gRPC other places in your stack. If you want the IDL you can use protobufs over plain HTTP.

GraphQL solves a very different problem and I would generally not consider it as an alternative to gRPC.


Agreed, I think most people miss the point that most protobuf implementations support JSON and/or binary across the wire. We flip an accept flag for the frontend and we get well structured JSON.


Have used both, and don’t like either. I actually DO like very statically typed schemas, but you can easily do this with json over REST, and using IDLs to generate SDKs.

For gRPC vs. REST, I just don’t see the benefits. Performance wins of gRPC are extremely minimal for most backends, ”push based” workflows can easily be handled with webhooks (or message queues), so why am I throwing out extremely mature technology (and tooling/middleware!) that every dev is very familiar with?

For GraphQL, reducing client/datacentre round trips is nice, but can also easily be achieved with RESTful “coordination” services, that serve the front end specifically, and do nothing but stringing together calls to backend services. Why force people to learn another complex technology for that? “Returning smaller payloads” makes minimal impact in practice, and GraphQL requests are MASSIVE compared to REST requests, so you often end up with a performance loss, not gain. Also, GraphQL requests are way harder to glance at in the browser, you can’t just look for GET /dog/123, you have to peek into all the request bodies. And again, all the great REST middleware stops working, because you’re doing RPC.

Basically I see them both as extra complexity with little payoff.


> For GraphQL, reducing client/datacentre round trips is nice, but can also easily be achieved with RESTful “coordination” services, that serve the front end specifically, and do nothing but stringing together calls to backend services.

I mean . . . that's all a GraphQL "server" (or parser/aggregator endpoint) is.

> Why force people to learn another complex technology for that?

Because most later-stage 'RESTful “coordination” services' like you describe probably already include: 1) a DSL of some kind for expressing what data you like; 2) significant complexity for expressing grouping or deduplication logic; 3) complex requirements for coordinated backend services so that their "raw" data can be rolled up un an efficient and uniform way by the coordinator.

That's complex, and new to most people--pretty much everyone who starts work on it, if you built it yourself. GraphQL queries and aggregation layers are similarly complex, but new to fewer people, and better supported.

I think there are some big problems with GraphQL as a concept/technology (I am currently pushing back against its adoption in my area), but the above are not the right criticisms.


Curious to know if you would count "ecosystem" as a point towards either? Afaik there isn't a standardized way of creating statically typed schemas for REST. A standard statically typed schema like GraphQL's allows a community to create and maintain tooling around it. A person would create"[some tool] for GraphQL" instead of "[some tool] for [specific api]"


In theory, yes, but in the case of GraphQL, I found it was very difficult to generate schemas dynamically. Factoring out common fields was not possible. Common fields in schemas had to be duplicated and there was no concept of an include/mixin/extends/etc. Best technique was generating plaintext strings of GraphQL programmatically (losing any editor or type checking support). Dropping down to the AST layer of GraphQL is a bit more programmatic but not really an ideal level of abstraction to work at. It was too verbose and low level.

REST integrates well with native JS constructs (it's just data) so it's much easier to compose and use metaprogramming techniques.


There's Open API Specification (Swagger). It's more documentation than strict protocol enforcement though.


You can have conditional protobuf fields / messages.

Checkout:

- Any: https://developers.google.com/protocol-buffers/docs/proto3#a...

- OneOf: https://developers.google.com/protocol-buffers/docs/proto3#o...

I believe Any is the equivalent to having a proto in format of:

```

message MyMessage {

    string type = 1;

    bytes data = 2;
}

```


Also FieldMasks and the View patterns can be very useful for the other issues that were raised https://cloud.google.com/apis/design/design_patterns#partial...


We use both, gRPC for backend services and a GraphQL server that aggregates and communicates with those services for the frontend. Because the backend is all described with .proto files its trivial to autogenerate most of the GraphQL server that serves the fronted. Tends to be the best of both worlds, IMO.


> I've tried both in the past and found that APIs are rarely as static as typed API systems require. Many APIs have fields that are required conditionally based on the value of other fields. Other times the schema is dynamic and workarounds are required like stuffing things into a JSON object and making it a "string" in the API.

There are big advantages to strict, mostly-static, clearly typed APIs, but you're right that adoption is often tricky. The problem isn't the nature of typed APIs, or missing capabilities in the data transfer formats/communication libraries themselves.

The problem is tooling.

Put another way: the tipping point (between untyped/whatever-you-like JSON and something structured like gRPC) is not how easy it is to use already-existent strict/typed APIs, but how easy it is to add, deploy, and change them.

API and client developers will stop pushing back on a structured format, or adding workarounds (like stuffing random JSON into string fields) if the tooling that supports changing API definitions is excellent: if they can easily change the minimum of code or type definitions to make the data-"shape" (schema) changes they want, and immediately be able to exercise their changes across multiple backend APIs and frontend clients (with obvious and predictable behaviors around versioning and backwards/forwards compatibility), and can have confidence that they can deploy those changes to real users in a seamless and low-touch way (e.g. no "everyone please update your endpoints to /api/v804.7/"), then resistance/workarounds to structured API patterns will disappear.

There's some expertise/discipline involved in getting those things right, but they need to be easy first.

The companies that have really gotten huge benefits from stricter, more uniform, generated and/or typed API definitions (for both internal service interactions and external clients) aren't all huge companies, they aren't all using the same tech stacks, and they aren't all in the same kinds of markets. The thing they have in common is a huge investment in good tooling around how to create, modify, and deploy cross-platform typed APIs.


We've been using gRPC for a new web project and it has been a good experience so far. The codegen in JS is pretty verbose and can have touch ergonomics, but not the end of the world. We haven't ran into troubles with the type system, but we leverage OneOf's and Views a decent amount. The thing we don't have a great solution for right now is how to fetch referenced types efficiently (eg. stream of posts with users referenced by a foreign key), but we're not tackling that until performance of the resource fetches becomes a problem and evaluating whether to cache values client side or design a solution at the API layer.


What does GA mean? The article uses it a few times but doesn't define it.


I think it may be aligned with GCP terms here: https://cloud.google.com/terms/launch-stages

General Availability (GA) GA features are open to all developers and are considered stable and fully qualified for production use.


I've taken your phrasing and addressed OP's question in the blog. Thank you. :)


General availability (GA) is the marketing stage at which all necessary commercialization activities have been completed and a software product is available for purchase, depending, however, on language, region, electronic vs. media availability.[12] Commercialization activities could include security and compliance tests, as well as localization and worldwide availability. The time between RTM and GA can be from a week to months in some cases before a generally available release can be declared because of the time needed to complete all commercialization activities required by GA. At this stage, the software has "gone live".

[0] https://en.wikipedia.org/wiki/Software_release_life_cycle#Ge...


Alpha/Preview => Beta => General Availability


I prefer twirp's model of no http2 requirement and supports JSON. https://github.com/twitchtv/twirp

I do think twirp code could be refactored and made a lot better though.


If twirp had more existing backend implementations, I would certainly use it for more things.


Check out Thrift: https://thrift.apache.org/


Anyone willing to share experiences using gRPC-Web vs. GraphQL?


Conceptually, gRPC gives much more server predictability at the expense of client flexibility whereas GraphQL optimizes for the opposite. Sure you can have gRPC calls with lots of client options or GraphQL servers with lots of restrictions. There are security/performance concerns around client flexibility and time-to-market concerns around server-side rigidity. I prefer the latter in most cases and don't expose GraphQL on the public web (again, I know GraphQL can be secured and made more predictable/inflexible).


As I understand it, they are essentially very different technologies. GraphQL focuses on providing a DSL for requesting subsets of data from a web endpoint that "talks" JSON. gRPC-Web is just a wrapper around gRPC so that you can expose your RPC endpoints in a front-end friendly manner.

In other words: GraphQL is akin to SQL, while gRPC-Web would be closer to a serialization/exchange format like XML/SOAP.


gRPC is lightweight, highly performant, difficult to debug, difficult to detect breaking schema changes, lots of magic going on to learn compared to REST or GraphQL.

GraphQL is much heavier, easier to test and debug and has some performance optimisations like data loader and is better for multiple clients to consume. I’d say it’s easier to manage schema changes but it’s probably not empirical. I guess huge overheads by comparison to gRPC but I’m guessing data over the wire is a much larger piece of the pie.

Personally think GraphQL is far superior for web clients and I think gRPC for services in general can be a pretty large overhead for most teams... at least initially you are going to get things done much faster with restful services.


as someone without experience in gRPC but interested to use it, I am curious why it was difficult to detect breaking schema changes?

thanks


Because the schema is based on a numbered position rather than a field name. This means you need to never rename positions - if you want to deprecate fields you just loose the numbering. Numbers 0-15 use less space in the message than others for example.


I was thinking the same. I’ve often seen GraphQL contrasted with just REST, and likewise the OP talks about gRPC-Web vs just REST.

I performed a web search and found some articles comparing the three together, the first among which [1] I will proceed to summarize.

This article gives an overview of how GraphQL, REST and gRPC work and then provides some opinions on which situations each of them are most suitable in, and also includes examples of companies and services using/implementing each of the three (as well as additionally doing the same for Webhooks).

Note that it speaks of gRPC, not gRPC-Web, so you have to keep in mind that when they talk about gRPC some of the things they are saying do not apply directly for gRPC-Web. I think however that this article is still relevant if one takes into account the details about gRPC-Web from the OP.

The presentation of each of the four is consistent with what I know about REST and GraphQL from having read about them and having worked with REST (both on the consumer and as provider sides) as well as having explored GraphQL a bit, so I am inclined to believe that they know what they are talking about.

Near the end of the article they offer the following opinions for which is appropriate when:

> REST: A stateless architecture for data transfer that is dependent on hypermedia. REST can tie together a wide range of resources that might be requested in a variety of formats for different purposes. REST is fundamentally concerned with stateless resource management, so it’s best used in such situations. Systems requiring rapid iteration and standardized HTTP verbiage will find REST best suited for their purposes.

> gRPC: A nimble and lightweight system for requesting data. gRPC, on the other hand, is best used when a system requires a set amount of data or processing routinely, and in which the requester is either low power or resource-jealous. The IoT is a great example of this.

> GraphQL: An approach wherein the user defines the expected data and format of that data. GraphQL is from Facebook, and that pedigree demonstrates its use case well — situations in which the requester needs the data in a specific format for a specific use. In those cases, those data formats and the relations between them are vitally important, and no other solution provides the same level of interconnected provision of data.

> Webhooks: Data updates to be served automatically, rather than requested. Finally, Webhooks are best used when the API in question primarily updates clients. While such APIs can also have other functions, even RESTful ones, the primary use of a Webhook microservice should be to update clients and provide updated, provisioned data upon the creation of the new, updated resource.

> Choosing amongst these specific options is really a matter of aligning your business functions with the appropriate approach, and ensuring that the systems in place respond within the given parameters.

I found the article to be well written, thought out, and to answer the question I had in my mind. The whole thing is worth a read.

[1]: https://nordicapis.com/when-to-use-what-rest-graphql-webhook...


Great link and summary. Thanks!


This is all well and good but examples only ever show localhost quick projects. I’d like to see the demo game upped a bit to include some basic auth and HTTPS stuff


There is a gRPC-Web on Kubernetes example here: https://github.com/salrashid123/grpc_web_with_gke



that's good feedback, can I request you to file an issue detailing what you would like to see in an example? https://github.com/grpc/grpc-web/issues


I think GraphQL makes more sense here, at least in terms of unifying backend services and presenting them to a user—aka an API gateway—but this could be a very useful way to transmit GraphQL queries and subscriptions and for sidecar services like authentication, or just very simple services.


I am using the HTTP Gateway and generating OpenAPI from that for type-safe access [1]. The downside is that this introduces an additional build step in your project.

The upside is supporting a JSON API and not requiring gPRC(-Web) for clients. Even for non-browser clients, GRPC tooling can still be a little heavy-weight to pull into your project compared to OpenAPI. On the other hand, not all languages have good OpenAPI integration.

But its also quite possible to use both.

[1] https://github.com/gogo/grpc-example


I thought this was interesting from the roadmap:

"The binary protobuf encoding format is not most CPU efficient for browser clients. Furthermore, the generated code size increases as the total protobuf definition increases.

"For Google's Web applications (e.g. gmail), we use a JSON like format which is comparable to JSON in efficiency but also very compact in both the message size and code size."

I wonder what the benchmarks look like? It seems surprising this hasn't changed with newer browser optimizations.


Proto encoding makes the unfortunate choice of more-bit variable-length numbers which are hard to decode. JavaScript engines and browser all have very well optimized decoders for the unary length-prefixed variable-length numbers (i.e. UTF-8). So you can imagine how an encoding very much like proto but with the proper style of varints can be faster.

Generated code size is a huge problem of all protobuf-supporting languages, not just js. Code size issues on Android have constrained development of the official (google) protobuf libraries in various ways over the years.


Anyone here knows if gRPC-Web provides performance benefits as opposed to using REST?


RethinkDB switched away from Protobufs (which underly GRPC) in favor of JSON when talking with both Python and Ruby clients because it was so much slower than using JSON. My guess is that this is still true, and even worse for JavaScript (that last is pure speculation). But I would be happy to see real benchmarks done now.


Python protocol buffers can use either a native or a C++ implementation. The latter is more than an order of magnitude faster. I'm wondering if they tried that. It doesn't solve the Ruby case, of course. Or JavaScript. gRPC can also use Flatbuffers, by the way.


The performance benefits of Protobuf serialization and deserialization are extremely variable by language; JSON is faster in Python while Protobuf is significantly faster in Java and Golang. JSON is pretty fast in JS (unsurprisingly) but perhaps Google is working on optimizing protobuf in JS.


What's the advantage of gRPC-Web to someone in the .NET world that uses Typescript, and generates TS schemas from .NET POCOs ?


Protobufs (the transfer format of gRPC) include not just a schema, but a transport format that may be more efficient than a serialized POCO.

gRPC also allows you to encode communication semantics (i.e. "What does this endpoint want as arguments? What does it return?") and generate both client and server code that complies with (and automatically [de]serializes and validates protobuf data for) those semantics.

It's the difference between a schema definition and a schema definition + serialization format + service (not just data) definition/codegen.


Has anyone gone from plain text JSON to protobuffer (over Websocket) ? How much bandwidth did you save, and was it worth it ?


How does this compare to JSON-rpc or GraphQL or just using JSON to send custom messages over HTTP 1.1 or HTTP 2?


Isn't this just WCF reborn? Contracts, codegen no one will use, etc


Awww, man. I like WCF; wish more people would use it (and use it right).

So much of the stuff I've had to do there is untangling the work of people that fundamentally don't want what WCF provides (quick, one-size-fits-all-imperfectly prototyping with an option for greater flexibility later on), and instead want 'automatic contract enforcement, but I still get to write the client/server code from scratch the way I used to', which is a recipe for sadness.


>Every old idea will be proposed again with a different name and a different presentation, regardless of whether it works.

https://news.ycombinator.com/item?id=18296113



Thus ends REST.


Cue the relevant xkcd standards comic.


Personally I don't think that gRPC is a good step forward.

However, if the community at large moves away from REST + JSON to gRPC I'll follow.

Why?

- I don't want to be like the guy who refuses to use anything but XML + SOAP

- I want to be valuable on the job market. Putting gRPC may get you in the door

- Avoid bikeshedding

Anyone who's been in the industry a few years knows that "the way" to do things changes often. Going with the flow and completing the actual job is what matters.


I found gRPC to be exciting when I was writing something in Go. The tooling around that is pretty decent and it sets a certain expectation about how it works.

Then I had to write a client in a different language, and the generated code was utterly intuitive. gRPC itself adds extensions to Protobuf to handle code-gen nuances but of course they're deployed in Go-land, not relevant-language-land.

That's a small niggle that's easily solved one way or another. What was frustrating was that the `protobuf` CLI could handle language extensions, but you couldn't make use of that without a hell of a lot of faff. If you want to add a gRPC client to your Rails app you can't use the protobuf CLI, that you might already have.... you have to add a gem that includes a different version of the protobuf CLI that is guaranteed to be not compatible. Even the command and its args aren't compatible.

When I found myself working against that I just gave up. It's a solution that sounds elegant, but you're going to get a feature out of the door much quicker if you steer away from that layer altogether. There's nothing wrong with an ad-hoc HTTP API if you're confident about the interface.

Technical purity isn't technical excellence and nor is it user value. Just like K8S, you're not gonna need RPC on the web unless you can justify the scale and have the firepower to handle it.


Mind commenting on what you think would be better?

Personally I'm in love with the idea of protobufs, but I'm not terribly sold on the implementation. The language is great, but the mapping to code languages is not great. Eg, to make great idiomatic Go code, I need to litter my Protobuf with extensions (via Gogoprotobuf) and the readability of the Protobuf sort of goes down the tubes.

So I think the idea behind Protobuf is great, and the syntax itself looks great, but a small tweak to how it handles code generation would be very welcome.

Likewise gRPC feels quite verbose. I use it, but conceptually I massively prefer simplistic implementations like Twirp[1]. However, again Protobuf handles this really nicely in that I can use the same Protobuf file to describe a Twirp or gRPC Service - it's great.

[1]: https://github.com/twitchtv/twirp

So what do you think would be a better step forward?


I think that if we're going to have a full blown typed RPC system, we need to at least be able to represent generics/parametric polymorphism. As far as I know, protobufs do not support this feature! Why are we settling for using a subpar interchange format when the alternative (polymorphic sum types) is so much better?


Can you give me an example where generics would be helpful? I'm not doubting you, my brain is just a little slow today and I'm struggling to think of a scenario where I feel I would NEED them for gRPC.


Option<T>.

Protobuf "supports" this particular case via other means: messages are always implicitly nullable, and the WKTs cover primitives, which don't count as messages.

Map<K, V>: Protobuf has dedicated syntax for this case.


Generics and user defined types make it easier to represent more complicated data. Now everyone is just going to have to write custom encoders and decoders to get the data to a Protobuf compatible format, which is pretty much what we do right now with JSON.

If you haven't used algebraic/sum types before, I highly recommend trying them out. Once you use them you won't want to go back.


If I was to design a type system I would introduce sum and product as type constructors and some basic types and be done. To make this really work takes polymorphism so you can write list.


gRPC is not "typed" in any substantial way. You wan use any payload encoding you feel like suits your worldview. Protobufs happen to be a common choice.


The gRPC website mentions protocol buffers in the first sentence, and the Wikipedia page says that protocol buffers are used for gRPC. I consider a defacto standard to basically be equivalent to a standard, even if that's not "technically correct".


It is true that gRPC tends to implicitly imply Protocol Buffers. It's the only format that is worked on directly by the gRPC team.

However, C#/C++ Bond, C++ FlatBuffers, and Java Avro have some level of code generation support for gRPC. I'm not very familiar with Microsoft's Bond, but it appears to have generics for both the service and structs.

disclaimer: I'm part of the gRPC team.


It's interesting to watch Google's moves to control every part of the stack. Browser: Chrome. Frontend: Closure compiler -> obfuscated SPAs. Transport: gRPC. Backend: Proprietary Google software written in Golang. Orchestration: Kubernetes. Hosting: Google Cloud. Etc. You can imagine a future where Google services are no longer just web apps on the same footing as anything else in the web ecosystem, but where every step of the development, deployment, and end-use is managed by Google. Can't blame them for doing that, I'm sure it's more efficient, but it's definitely moving the web in a different direction, one where Google has more control at the expense of everyone else (end users, competitors).


They're not controlling anything by releasing open-source libraries/languages such as gRPC, Kubernetes and Go. Releasing these things don't give them control over anything that can negatively impact users; this is not Microsoft's embrace-and-extend.

Chrome, on the other hand, is worth worrying about. Unlike the other technologies you mention, it's a consumer application that legitimately lets Google apply Microsoft-style embrace-and-extend tactics, monopolizing the web and steering it in a direction that benefits Google more than anything (e.g. ads and tracking).

Kubernetes may have come out of Google, but it isn't even in their control anymore. If anything, Kubernetes is a strategic play to democratize cloud orchestration, undermining competitors such as AWS.


Good points. I don't see anything wrong with these individual open source releases. See my other comments about the larger trend this represents.

"Releasing these things don't give them control over anything that negatively impacts users" and "undermining competitors such as AWS" contradict with each other if you believe competition is good for users. The decision to release something as open source doesn't happen in a vacuum. Open source doesn't automatically make corporate activity morally good or neutral.


gRPC, Chrome and Closure are all open-source, Closure comes with source maps, and the "Proprietary Google software written in Golang" backend is pure speculation.They might turn out to be the Borg, but this release isn't part of of the assimilation process.


"It's open source" isn't the full story. Something can be open source and also used in a harmful way. You're right that gRPC-Web alone isn't a huge issue, but it's part of a larger trend of Google wanting to Google-fy the web, technology, or even society as a whole (see the leaked Selfish Ledger and Good Censor presentations).

Specifically in the case of gRPC-Web, even though "it's open source", does every gRPC service exposed on the web provide a .proto file for you to build your own client? If not, that's a big step down in terms of power given to end-users compared to REST.


Google is externalizing a lot of tools used internally for years. Use them or don't, it's your choice, but lots of time and effort has gone into making them work well so there's value there being made available for free.

To your point about .proto files for public endpoints: does every JSON HTTP endpoint exposed to the web provide documentation for you to build your own client? (of course not)


Again, I don't think this specific example is hugely significant, I'm looking at the larger trend.

Re: public endpoints. Say you're poking around a public web service, and it doesn't provide an API. Maybe you're writing a browser extension. Would you rather reverse engineer a JSON HTTP API with no documentation, or a gRPC-Web API with no .proto file?


$ grpc_cli ls <addr>

You’re welcome.


That looks useful. Do you know if that works with gRPC-Web where the underlying gRPC port is behind a service proxy?


It shouldn’t be a surprise that the company all-in on the Web has a solution for every part of the stack. It might be a surprise that they open source so many things but that’s a pleasant surprise. Every thing you mentioned has a replacement from someone else so I don’t see how you concluded “control”. And finally the great majority of Google’s backends are written in C++ not Go.


Many companies are "all-in on the web" but aren't in the same position as Google. Look at the recent Chrome profile / Google account auto-login issue. Isn't that an example of Google exercising "control" over how its users interact with the web?

If Google is effectively a monopoly, does it matter if you could theoretically replace all of its offerings? Think about other monopolies in history, I'm sure they had "replacements" too.


That is not accurate. If you went head-to-head with the Standard Oil Company they would send a guy over to blow up your house. The East India Company was based chiefly on genocide and high seas piracy. All this yip-yap about Google being a ruthless monopoly on a historic scale is completely ridiculous.

As for the Chrome login thing, being logged in on Chrome does not in any way shape or form alter the way in which Chrome interacts with non-Google sites or services. So I don't see how it is an example of how Google exercises control over the web. Certainly not in a world where I need only drag Chrome into the trash can to switch browsers (and, indeed, on a computer where Apple constantly exhorts me, in a way I cannot disable, to switch to Safari instead).


don't forget office suite:gdoc, and conferencing: hangouts/meet/whatever they force down your throat tomorrow. this is specially pernicious as they are actively using it to undermine Firefox in the workplaces. their proprietary plugin took 2 months to be available in Firefox after they rebranded hangouts as meet. and now it only supports SD video and crashes frequently.


Http/2, spdy


This is going to enable so many people to find-replace “Thrift” with “gRPC” for such an easy solution to updating legacy Slack messages, GitHub issues, and message board threads.

Updating your outrage at a stupid tool nobody should use has never been easier!




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: