gRPC-Web is going GA
cncf.io
cncf.io
.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.
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.
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
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
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?
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.
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.
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.
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.
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...
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.
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.
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.
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.
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.
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.
(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...
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.
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.
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.
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.
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.
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?
grpc/grpc-web intends to support the same: https://github.com/grpc/grpc-web/blob/master/ROADMAP.md#loca...
I think the full set of differences can be found here: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md
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.
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.
HTTP was designed for file downloads and uploads while. WebSockets was designed for raw data.
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.
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;
}```
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.
REST integrates well with native JS constructs (it's just data) so it's much easier to compose and use metaprogramming techniques.
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.
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.
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.
[0] https://en.wikipedia.org/wiki/Software_release_life_cycle#Ge...
General Availability (GA) GA features are open to all developers and are considered stable and fully qualified for production use.
I do think twirp code could be refactored and made a lot better though.
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.
thanks
In other words: GraphQL is akin to SQL, while gRPC-Web would be closer to a serialization/exchange format like XML/SOAP.
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...
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.
"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.
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.
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.
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.
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.
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?
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.
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.
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.
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.
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.
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).
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.
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)
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?
You’re welcome.
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.
"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.
Updating your outrage at a stupid tool nobody should use has never been easier!