
gRPC-Web: Moving past REST+JSON towards type-safe Web APIs - bestan
https://spatialos.improbable.io/games/grpc-web-moving-past-restjson-towards-type-safe-web-apis#hn
======
andrewingram
I first saw this one a few weeks ago, and have been trying to weigh up its
pros and cons over GraphQL (my tool of choice).

gRPC-Web:

* Speaks protocol buffers, a fast and compact format compared to JSON

* Allows clients to use the same APIs as backend services.

GraphQL:

* Enables a client-centric view of the system. I have abstractions in my GraphQL server that only make sense to clients. It's a query-centric implementation of the Backend-for-frontend pattern, where the owners of the service are also the consumers.

* Enables an entire UI's requirements to be fetched in one go (or optionally split up, if some content is less important). To achieve the same level of aggregation performance in gRPC would require building something analogous to GraphQL.

The other benefits of gRPC-Web outlined in the article (generating typescript
bindings) are equally possible with GraphQL (Relay Modern generates flow
types, and is probably just one pull request from supporting TypeScript too)

The status code standardisation only makes sense for single-purpose
endpoints/calls, once you're dealing with aggregations, the semantics of a
downstream status code will vary depending on the use case the query fulfills.

I think both solutions have use cases, and can even happily co-exist. I don't
believe gRPC-Web to be as much of a game-changer as GraphQL, but for certain
scenarios (needing to rapidly fetch streams of data that don't have cross-
dependencies) I can definitely see the benefits of a solution based on gRPC.

~~~
decwakeboarder
> Speaks protocol buffers, a fast and compact format compared to JSON

This is definitely important at Google-scale, but for the rest of us
compressed JSON typically isn't that bad.

~~~
euyyn
If your users access your website from their phones, the latency and CPU
benefits of proto become important for them.

------
runeks
I don't understand this, to be honest. What does type safety have to do with
serialization formats or application protocols? I've used Servant (Haskell) to
define the REST API for my backend, which gives me type safety, server stubs
and generated client code for free. In my view, type safety is about what you
internally use to represent your API, and has nothing at all to do with the
underlying protocol(s). There's nothing about REST+JSON that prevents type
safety, as far as I'm aware.

I plan to switch to protobuf3 for the serialization format, since this offers
both a JSON and binary representation. Why would I want to choose gRPC+proto3
over REST+proto3?

~~~
IshKebab
> There's nothing about REST+JSON that prevents type safety, as far as I'm
> aware.

Well, except for the fact that JSON is pretty much untyped? I don't understand
what there is to not get. If you want type safe RPC you have to use an RPC
system that at least _has types_! What stops me sending `{ name: 12, age:
"Hello"}` to your JSON RPC system?

~~~
cle
JSON is just a serialization format. Everything you send over the wire is just
a bunch of bytes, including JSON and protobuf. JSON has types, and you can use
it with a typed RPC system just fine. Whether or not clients can deserialize
something you send them can't be known statically, even with protobuf.

> What stops me sending `{ name: 12, age: "Hello"}` to your JSON RPC system?

Nothing. And the same applies to a typed RPC. You don't have to use the typed
client. Or you could be using an old version, or it could be misconfigured,
etc. You can enforce schema on the server and client side, but you'll never
really know if it works statically, since you don't compile and deploy the
server and client atomically.

~~~
computerex
Yes you don't have the guarantees of statically compiled/linked code but the
entire point of using protobufs is that if you use the generated interfaces,
you'll end up with fast binary serialization/de-serialization with type
safety. That's a lot better than just using JSON. Which is very verbose.

You could of course make your own protocol and type system and use JSON for
transmission. Why bother when this is done for you and is likely going to have
the best adoption when it comes to interface definition languages like
protobuf or Thrift.

~~~
cle
I agree, I love protobuf and JSONSchema and Thrift, I think they're great
ideas that solve important problems.

But the hype is getting carried away--they aren't a silver bullet for
distributed systems, they're just a way to manage schema. Define a schema in
an IDL, and Protobuf/Thrift/whatever generate schema validators and
serializer/deserializers for clients and servers. But they are not type safe
across systems, and that they compile doesn't imply anything about whether
they will actually work at runtime.

~~~
stickfigure
Sure, and gRPC doesn't guarantee that the server is turned on when the client
makes a request. Some expectations are unreasonable.

On the other hand, if you publish one set of proto files and all clients &
servers consume these artifacts, the system as a whole is more "typesafe" and
reliable than if you just post swagger docs and expect all your developers to
check them daily for updates.

gRPC means API changes stand a good chance of getting caught by build systems.
That seems about as reasonable a definition of "type safe across systems" as
can be expected.

~~~
cle
I agree completely which is why I love proto.

------
grw_
The reference implementation of gRPC on github[0] has 998 open issues and 215
open pull requests. Every time I've tried to use this package I have
encountered a previously-reported issue which has remained unfixed for months.

If you need to interact with Google platform it's hard to avoid using gRPC,
since many "official" libraries seem to be migrating towards this library,
while it remains fragile and bug-ridden. My "days since gRPC problem" counter
is currently on "2", after hitting an issue which /crashed my python
interpreter/ and required altering apache config to workaround[1].

[0] [https://github.com/grpc/grpc/issues](https://github.com/grpc/grpc/issues)

[1]
[https://github.com/grpc/grpc/issues/9223](https://github.com/grpc/grpc/issues/9223)

~~~
lyschoening
It is worth pointing out that the Python implementation is particularly bad.
Perhaps gRPC is really pleasant to use with Java and Go, but the Python
implementation is neither usable nor stable enough for it to be worth
considering its use for one's own services.

~~~
JayOtter
My instinct would be that it'll be just inherently nicer to use in a
statically-typed language.

~~~
lyschoening
Python can be statically typed.

------
mvitorino
I think I like gRPC, but have several reservations regarding replacing REST
with it. REST web services often return multiple mime formats, not just pure
structured data. Some services return images, others return HTML, and then you
also have cache... Maybe I just don't know enough about gRPC, but I can
already imagine many people passing images around as byte arrays inside
protocol buffers and when we look back, we have reinvented SOAP, which
reinvented Corba.

~~~
cshenton
gRPC generates rpc server and client stubs based off a protocol buffer
definition. Saying it's a replacement for REST makes little sense since it's
possible to define a REST API within it. It's also possible to write a totally
not RESTful API in a modern http api framework.

In fact that's what Google's API design guide does. Encourages RESTful API
design then describes how to implement them using proto and gRPC.

The more interesting tradeoffs are proto vs json or other and how this
restricts message patterns to request/response (rather than pub/sub or
push/pull)

~~~
mvitorino
Interesting! When I first looked at gRPC I missed the option(google.api.http).
Are you aware of the reason why REST mapped gRPC is not possible in GAE (http
1 only on the server end of our code)?

~~~
mwitkow
There's actually a stand-alone proxy that translates the REST mappings of
`google.api.http` into gRPC requests. It relies on code-generation:
[https://github.com/grpc-ecosystem/grpc-gateway](https://github.com/grpc-
ecosystem/grpc-gateway)

This has been the way we've been shipping our REST services until now, but the
need to recompile the proxy was a major hinderence to our development speed.
Hence gRPC-Web implementation.

------
lstroud
Stub generation? Remote access protocols? CORBA all over again?

So, now I know the next big thing. Portable distributed objects. :-P

~~~
lvh
CORBA tried to make remote calls look local. Making them look remote (and
potentially even making some local calls look remote) is a very different
design principle that leaks through almost every bit of the standard, and
definitely leaks through to every bit of the implementation.

~~~
oconnore
It's funny to complain about CORBA's local/remote muddling in 2017 when we
have moved on to microservices that also talk to each other locally with
TCP/IP.

------
archgrove
Everything old is new again, except tunnelled over HTTP.

~~~
breakingcups
You mean like SOAP?

~~~
sheeshkebab
Like CORBA, EJB, RMI, and a pile of other rpc libs and specs that died over
the past 40 years.

------
zargath
Another hammer to a multifaceted problem, keep in mind that people have a lot
of different use cases where JSON REST API's are the lesser evil.

I only skipped through the spec for gRPC, but the protocol seems very limited.
I dont like the 'gRPC status codes', where HTTP status codes at least can be
grouped in ranges.

The abstraction from the technology/protocol should not be the issue compared
to the abstraction from the core business logic. When handling multiple
consumers, customers and technologies I tend to worry more about where logic
is handled and where data is stored, compared to how its transferred.

------
rdtsc
REST + JSON is simple, easy to debug, and it does the job. Web clients speak
JSON, servers speak JSON, humans can read JSON usually. JSON can be gzipped so
you get some benefit there.

gRPC is another large pile of foreign C code that's essentially a black box.
If there is a buffer overflow there that your code hits only somehow, you'd
have to know how to debug it and fix it.

Also chances are you are not Google, Facebook or Amazon , and you don't really
do BigData just your know, regular data.

~~~
ska

       and it does the job.
    

It does _some_ jobs admirably. Because of the tooling and familiarity, it's
often asked to do other jobs, and here the results are decidedly mixed.

------
TimMeade
Just saw this during the morning reading. Without a deep dive, this looks very
promising. We have recently been moving to k8s and grpc for our node work and
the last piece was how to get to the browser. If this ties it all as one
straight protocol from db to browser it will be very welcome and could not
have come at a better time. We were evaluating the alternative (GraphQL etc)
but our experiences with node and grpc have been excellent so far.

Immediate evaluation planned.

~~~
mwitkow
That sounds very much what we're doing, except our microservice stack is in
Go. For nodeJS you probably want to front your pods with grpcwebproxy
([https://github.com/improbable-eng/grpc-
web/tree/master/go/gr...](https://github.com/improbable-eng/grpc-
web/tree/master/go/grpcwebproxy))

If you hit any snafus, please file bug reports in
[https://github.com/improbable-eng/grpc-web](https://github.com/improbable-
eng/grpc-web) We're happy to help :)

~~~
TimMeade
Much thanks. I'll add it to the immediate list.

------
Gigablah
The title ("by Google and Improbable") is a bit misleading since it implies a
collaboration between the two, when it's actually Improbable's own
implementation that they released ahead of Google's pending spec.

~~~
mwitkow
One of the authors here.

This is indeed our own implementation of the pending spec. We are in touch
with the gRPC team to make sure that their (still unreleased) implementation
is cross-tested with ours.

The benefit of our implementaiton is a relatively light-weight client-side lib
for Typescript and >=ES5, and a "ready-to-go" Go middleware.

------
devoply
Unless I need high throughput, I am sticking with JSON Rest as it's good
enough for most things and easier to debug by sticking a proxy in the middle
or using ngrep.

------
linkmotif
This kind of stuff couldn't happen soon enough. REST is so arbitrary and less
than useful for building UIs. It's just bad.

I've got Relay talking to a GraphQL service built in graphql-java which then
talks to a gRPC service layer. The gRPC service layer is a great fit for
GraphQL. Some type safety all around, but there could always be more. And
there could always be less JSON. Please, no more JSON. The only thing it's
good for is debug logging.

------
beastman82
I'm using my own gRPC services and Google's speech recognition gRPC API and I
absolutely love it. Protobuf/types, generated code, clear API contract.

------
grovesNL
I'm not sure why you need to modify your serialization or protocol to get type
safety.

I've been using NSwag
([https://github.com/NSwag/NSwag](https://github.com/NSwag/NSwag)) to generate
TypeScript clients from .ASP.NET controllers and it works great. It can
generate TypeScript request/response handlers, and interfaces or classes for
any public facing models.

------
westurner
Wikipedia:
[https://en.wikipedia.org/wiki/GRPC](https://en.wikipedia.org/wiki/GRPC)

Src: [https://github.com/grpc](https://github.com/grpc)

Docs: [http://www.grpc.io/docs/](http://www.grpc.io/docs/)

------
grizzles
Personally I'd prefer a promise based api. eg. stub.QueryBooks(qbr).then(...)

A benefit of grpc coming to the web means someone will inevitably build a tool
to parse a .proto file and generate a ui to test your microservices during
dev. That will be cool.

~~~
shaklee3
Not exactly a promise, but grpc has an asynchronous API.

------
didibus
I acknowledge it could just be me and the specific projects I worked on, but
I've never been encumbered by an API style. RPC, Rest, GraphQL, I almost find
them all to simply differ in syntax.

I've managed to solve all my use cases using all three with equal effort, time
and with comparable outcomes.

There's value in compression and faster serialization/deserializarion formats
when and only when micro-performance becomes an issue. Other then that, I
think programmers spend way too much time debating over these, where I don't
see any one of them providing an ROI advantage over the others.

~~~
andrewingram
REST (in the pure sense) vs RPC is a valid comparison, but GraphQL solves a
different problem. GraphQL is an alternative to other gateway API or backend-
for-frontend solutions.

The benefits of a gateway API to both developers AND users are hugely
significant. These are decidedly NOT micro-optimisation.

~~~
didibus
What's a gateway API? I acknowledge, I don't do a lot of frontend work. As I
see it, GraphQL is just a query syntax that uses a JSON like language and
where the query engine is built in code on the backend. You could replace all
queries by REST requests, or build your own query language on top of JSON or
RPC.

In my experience though, anything approaching a query language was too
expressive for an API, and it was better to offer one API per query, and
encapsulate the queries on the backend themselves.

~~~
andrewingram
Gateway APIs:
[http://microservices.io/patterns/apigateway.html](http://microservices.io/patterns/apigateway.html)

Assuming you've read that then I'd add the following. If you don't have
_something_ approaching a gateway, you're probably doing a big disservice to
your users (assuming clients fetch data via API, rather than using a
traditional render-on-the-server framework like Django or Rails).

The value proposition of GraphQL is based on the assumption you're already
doing things right by users, and its possible to fulfill the data requirements
for a single page or app screen in a single API call. What this probably means
is:

* You have a custom endpoint per screen

* That endpoint to either a) be versioned or b) support as many historical versions of your app as are in production

* You might have a gateway per client (this is the full backend-for-frontend pattern)

* Every time you add functionality, or change existing functionality, you're adding to what quickly becomes a huge set of endpoints

What GraphQL promises (and delivers on) is the ability to get all the benefits
of the backend-for-frontend pattern, without anyone ever having to write an
endpoint specifically for a give client use case. The clients convert their
data requirements into a query, and the GraphQL server returns the exact data
you need, no more, no less. It requires some discipline when it comes to
evolving the schema over time, but it works really really well. And when
implemented intelligently has comparable performance to hand-crafted endpoints
(I've written about how to approach this here: [https://dev-
blog.apollodata.com/optimizing-your-graphql-requ...](https://dev-
blog.apollodata.com/optimizing-your-graphql-request-waterfalls-7c3f3360b051))

When you experience the front-end workflow of using a library like Relay or
Apollo (both are GraphQL clients) and having perfect synchronisation with UI
and data, it's a really magical moment. You end up in a world where you can
just get on with building UI, it's amazing.

------
j_s
Don't forget to protect against malicious user input! There are both pros/cons
for 'non-human-readable' in the security department for sure.

 _Finding a $5,000 Google Maps XSS by fiddling with Protobuf_ |
[https://news.ycombinator.com/item?id=13829925](https://news.ycombinator.com/item?id=13829925)

~~~
deno
You can easily write an extension to in-browser Dev Tools to show human-
friendly representation of any binary protocol for development/debugging
purpose.

~~~
j_s
Nice. Are you aware of any Chrome extension for decoding Flash's
'application/x-amf' Action Message Format like Burp, Charles, and this Firefox
extension do?

[https://addons.mozilla.org/en-US/firefox/addon/amf-
explorer/](https://addons.mozilla.org/en-US/firefox/addon/amf-explorer/)

~~~
deno
Nope, sorry! But Firefox addons will be soon switching to extension format
compatible with Chrome, so you might get it for “free.”

------
progx
There is a reason why more and more people left RPC and use REST.

And for me "the next big thing" is something like GraphQL.

~~~
grizzles
Imo it was mainly poor language / framework support for asynchronicity. That's
not really an issue anymore.

~~~
pjmlp
So how is the modern way to work around issues like network partitions,
servers not responding, going off and on on network connections, duplicate
answers,....?

~~~
vertex-four
Futures-oriented programming - helped by the "async" or "generators" support
in quite a few modern languages. Wrap timeouts and retries around everything,
and process the timeout errors accordingly.

RPC doesn't mean that a remote function call looks exactly like a local one.
That was a mistake. Modern RPC systems return composable futures which make it
trivial to do timeouts and retries, send off many requests at once and wait
for all/some of them to return, and so on and so forth.

If you're doing something that shouldn't happen more than once, generate a
transaction ID to identify it by.

------
pspeter3
One cautionary tale is to avoid generating code that exists at run time with
Typescript. We managed to cause a severe page load regression for a while by
generating Typescript for each DbObject and Projection (similar to a
persistent GraphQL query).

My advice is to only generate types and interfaces if possible.

------
jupp0r
There is also Google's own implementation of this that has been in the works
for some time. See
[https://github.com/grpc/grpc/issues/8682](https://github.com/grpc/grpc/issues/8682)

~~~
mwitkow
Yea, we actually work closely with the gRPC-Web team at Google to make sure
our implementations are interoperable and we have plans for cross-integration-
testing.

~~~
jupp0r
Awesome, thanks for sharing this.

------
beders
It is still a bit shocking to see how many people are not getting the
distinction between an API and a RESTful service.

They are very different things and they have very different goals. The hint is
in: how much do you value the client?

If you have full control over both client/server or if we don't care about any
3rd party developing a client library for your service, then go with something
like GraphQL or gRPC or SOAP with a nice, typed spec you can generate your
code from and optimize the heck out of the bytes coming through the tubes.

If OTOH you have an interest to create a RESTful service that is discoverable,
that doesn't require constant client changes, that offer a wider variety of
resource representations, that need to stand the test of time, then use
HATEOAS and a RESTful architectural style.

gRPC is yet another ... RPC. Nothing good or bad about that. Just make sure
you understand the consequences.

------
yeukhon
But I always thought speaking HTTP with a server can be considered RPC. We can
pack our message in XML, JSON, or whatever serialization we choose, passes on
to the destination, unmarshall, do something, return.

------
daliwali
RPC has its own set of limitations, which if your application qualifies, might
be a good fit:

* Coupled server and client. gRPC uses protocol buffers which have zero backwards compatibility.

* Zero discoverability. The client knows in advance what the server can do.

* No standards to follow. You make up your own specs, like Google did.

These constraints are orthogonal to REST, the architectural principles behind
the web. What they're doing is tunneling RPC over the web, which is what most
HTTP APIs are doing already. There are only superficial differences like the
use of protobuf, lack of verbs and URIs, etc.

~~~
daliwali
I made a small mistake in the first point, got downvoted to oblivion and
people seemed to stop reading there: the binary serialization indeed has
backwards and forwards compatibility. However, the textual serialization lacks
this compatibility. I can't remember a petty detail of a vendor specification
apparently. Pedants with encyclopedic knowledge of Google are out in full
force today!

I should have stopped at "coupled server and client", the point is that they
both rely on an agreed upon external schema since the messages are not self-
descriptive.

~~~
Matthias247
Honestly: The other points are not better if your intention was to make grpc
look worse than other HTTP based APIs:

\- For all of them you need to know the remote addresses (IP/hostname, port)
upfront or use an external service discovery solution.

\- For both you can implement some service introspection, which delivers you a
list of available services/methods. Afaik for grpc there even exists some
standardized introspection mechanism. For other HTTP APIs you might want to
download some swagger description from a well-known address. Or WSDL scheme.
Or GraphQL schema.

\- Standards on which layer? On transport layer you are following the HTTP
standard, independent of whether you are using grpc, GraphQL, json-rpc or some
handmade REST API. On application layer you are mostly on your own anyway,
there's not a lot things one could standardize. There are some exceptions,
like the standardization of Webdav on top of HTTP, but most applications have
their own specific set of requirements. If we are talking about
standardization without meaning offical-standardization, then we can argue
that grpc provides a more rigid (standardized) model for an application than
the definition of some ad-hoc APIs: It is standardized how APIs and exchanged
data types are defined (.proto files), how they can be accessed and how data
is transferred over the wire (mapping to HTTP). All of that without the
application developers on both sides needing to care for it.

~~~
daliwali
Actually gRPC is about the same as other HTTP based APIs, it is just a more
efficient RPC. All of them are lacking what made the web scalable in the first
place.

\- HTTP APIs are worse than websites of the 90s. At least a browser could be
expected to view a few websites. HTTP APIs require a custom client for each
one.

\- Document media types, not APIs. This isn't such a novel concept, browsers
(fancy HTTP clients) work because HTML is a standard.

\- Standards at the application layer, not specifications. You mentioned specs
only.

Let me just clarify that RPC is a great fit if you are constrained to a single
vendor and don't care about third-party clients. On the web, every browser is
a third-party. For HTTP APIs to take off, they need to be built more like
websites, or else vendor specs will fill every niche.

~~~
euyyn
I don't understand your point about third-party clients. APIs defined in
.proto files can have both clients and servers implemented by anybody.

~~~
daliwali
APIs defined in XMLRPC, CORBA, SOAP, et al, can have clients and servers
implemented by anybody.

Programmers don't seem to learn from history and struggle with thinking over
time. These formats worked well in a time when a single party (or second
party) controls the server and client, when services were very consolidated.
Now that the web is becoming more and more centralized and closed, it follows
that RPC is making a comeback: widespread interoperability is not much of a
concern.

~~~
euyyn
Sorry but you're not addressing your own point:

> RPC is a great fit if you are constrained to a single vendor and don't care
> about third-party clients

If I'm not constrained to a single vendor, and care about third-party clients,
what makes RPC a bad fit? In specifics, not vague historical comparisons.

------
je42
Is this SOAP 2.0 ?

------
IshKebab
They sure do like spikes... whatever that means.

~~~
neon_electro
"A spike is a product-testing method that is used to determine how much work
will be required to solve or work around a software issue." [1]

[1]
[https://en.wikipedia.org/wiki/Spike_(software_development)](https://en.wikipedia.org/wiki/Spike_\(software_development\))

~~~
IshKebab
Ah, agile mumbo-jumbo.

------
godmodus
Scalakka devops represent!

------
jlebrech
why not emulate an RPC using webpack?

