3 ms·
I'm seeing a lot of comments here along the lines of "why even bother with protobuf (just use JSON, you fools!), and gRPC is a pain anyway!" There are two ver
by dimitropoulos 4y ago
I'm seeing a lot of comments here along the lines of "why even bother with protobuf (just use JSON, you fools!), and gRPC is a pain anyway!" There are two very very critical things to know if you find yourself thinking either of those two things:
1. To me the compression that protobuf offers, while cool, is not what I find most important about it (or, rather, is not the feature that I like the most). What is the most important (for me) is that the sterilization _forces your server and client to have a typed API contract_. This is a pretty big deal. Imagine you're in a situation where you spent months laboring over your OpenAPI config, just to later realize that
> _oops! my OpenAPI config doesn't actually represent what my server is actually doing, and now my OpenAPI generated user documentation is wrong, and my TypeScript types I generated from the OpenAPI config are wrong too, which means I'll get runtime `TypeError`s on the frontend.
This is a pretty common situation for people to find themselves in, and it's a tough spot to be in because... well... you can't ever escape. Because no one is really reliably generating actual running servers from OpenAPI configs, you hit this situation reallllly fast. Protobuf, on the other hand, is legitimately a spec-first workflow (by force -> which to me is a very good thing). Take a look at Postman's state of the API report, and you'll see that even their customers are only doing spec-first 10% of the time (and, this is supposed to be the cream of the crop in cutting-edge spec-first development). Why? Because it's really really really hard to do in practice. But protobuf makes it easy. That's a big deal.
2. gRPC and protobuf are not as deeply tied as you might think. You can use protobuf without gRPC at all, and in fact a lot of people are doing this. You can even do it over WebSockets, or anything else. Unfortunately, because the two technologies are often mentioned in the same breath we tend to deeply associate them. Years ago I had a project I needed to pick a wire compression thing for (it was just for fun) and since I was tired of always just using messagepack over and over again, I evaluated other options. I picked FlatBuffers in the end, but I wish I could go back in time and ask my past self why I didn't pick Protocol Buffers instead. I KNOW I remember looking into protobuf, but I think I just assumed that in order to do protobuf well you had to also use gRPC and since I wasn't up for learning gRPC, I gave up on protobuf. That's the beauty of what tools like Protobuf-ES are changing -> they're making protobuf accessible to everyone.
..and besides, there are other things that protobuf unlocks(namely the "reflection" API (very much like GraphQL's introspection API if you're familiar with that), but also things like documentation generation and enforcement of backwards-compatible changes) but the above are the two most appreciated by me.
- com2kid 4y ago> What is the most important (for me) is that the sterilization _forces your server and client to have a typed API contract_. I solved this by generating JSON schemas from my TypeScript files, and then enforcing those schemas on my endpoints. Using the magic of code generation (actually just templated strings) I am then able to create client libraries in whatever languages are needed. The unfortunate part of this is being limited by what TypeScript offers, no run time validation of the shape of fields, e.g. no way to say "this number has to be less than 120". JSON Schema is actually a lot more powerful than TypeScript, so going from TS->JSON Schema actually reduces expressiveness. But then again, the vast majority of programming languages don't allow for actually good descriptions of types. :(
- dimitropoulos 4y agore: TypeScript doing "this number has to be less than 120".. As a fun aside in fact you _can_ write this kind of type today (since 4.5 when they added tail-recursion elimination on conditional types). You can even do things like `Range<80, 120>` to clamp to a range. If something like "Negated types" ever happens (https://github.com/Microsoft/TypeScript/pull/29317 https://github.com/Microsoft/TypeScript/pull/29317) it'll make even more options available. Also, if you haven't checked it out, typescript-json-schema has some REALLY powerful validation it can do for things like your example (https://youtu.be/HHTDCY5uh_M?t=1379 https://youtu.be/HHTDCY5uh_M?t=1379). You can do stuff like this export interface Shape { /** * The size of the shape. * * @minimum 0 * @maximum 120 * @TJS-type integer */ size: number; } and regarding the part about generating JSONSchema from TypeScript files. I totally know what you mean, I think that approach really has great potential, but there's still nothing _enforcing_ that contract. If you care about the frontend and backend always being in sync (i.e. through deploys of the backend/frontend, but also in situations like many people find themselves in with dashboard web apps where users many not often refresh their page through many backend and frontend deploys), then you'll probably benefit from a tool like protobuf or GraphQL or any others that tries to help with this validation.
- com2kid 4y ago