This kind of "make the trivial part easy", "get started quick", "need no tooling" approach feels fast... at first, but then very quickly runs into nigh insurmountable problems.
A great analogy I heard was: "If your plan is to go to the moon, you won't get there by making a fast bus."
Is it neat they I can copy as curl a request to replay? Yeah. But, that isn't too hard to do with most any framework, is it?
Advice that I provide to dev teams is that every time you introduce a network hop, you're more-or-less going to triple the complexity of that interface boundary.
Before, where you might have had a simple function call such as "foo(p1,p2);", you now have to:
1) Define a message type that encapsulates the p1 & p2 arguments into a single thing.
2) Do this on both server and client, consistently, and allowing for versioning to handle rolling upgrades.
3) Encode and decode your actual programming types into this blob. (Across dissimilar languages this is especially fun.)
4) Write the "RPC server" code.
5) Write the "RPC client" code.
That last one is the bit that a lot of developers skip, or make it "other people's problem".
Imagine you're writing a server for an RPC endpoint. You (internally) define some return message type, call "toJson()" or whatever on it, return it from some HTTP REST route mapping... and you're done.
You're done.
You.
Queue the potentially dozens, hundreds, or possibly hundreds of thousands of developers that have to bang out the client side of this. By hand. Typing it in, based on your documentation... of which there is likely none. Or it's in HTML and not machine readable.
They're going to make mistakes. They will assume something is nullable when it isn't, or not-nullable when it is. They'll have no idea what error messages can be expected, or in what format, and the only way they'll find out is... in production. Rare errors they'll likely never handle properly.
Meanwhile, with "proper tooling" the server-side developer uses a formal Interface Definition Language (IDL) such as the one used by CORBA, DCOM+, gRPC, Cap'n Proto, or whatever. This IDL is ingested by tools(!) on both the server and client, generating reams of "stub" code, ready for business logic. Better tools will automatically insert the matching doc-comments, so that when typing in a proper IDE (which you use, right?), then hovering over a function definition will show its help summary text live, in context.
In enterprise settings, it's common to see code that's basically just a dozen APIs glued together to do something useful.
If those APIs are hand-rolled REST, then this takes months of development effort, and then endless maintenance as things just break in weird and unexpected ways... in production.
If those APIs are generated with tooling, then hundreds of kilobytes of that boilerplate RPC client code can be spat out in just minutes of effort.
More importantly, nobody then ever needs curl to diagnose random errors in production, because the code won't even compile if something doesn't match the schema. If something returns an unexpected value, nobody needs to inspect the wire traffic, because the deserialized value is in memory, visible to a debugger or log trace.
Getting "into the weeds" of banging out RPC requests by hand is for people that don't realise that they're not supposed to care what the wire format is!
It really is night & day. For example, back in 2006 with Windows Communication Foundation, you could just paste a single URL into Visual Studio, and then you'd be off to the races. It would generate everything for you, and you could just start programming your business logic immediately.
But it does not have to be this way. For my work, I've written a few smaller scripts that talk to things like Github and Jira using only python stdlib. There are no third-party libraries or codegen tools, there is not even install step - you check out the code and run, and it _just works_. And users love it and use every day, and the fact that I can tell them "no dependencies needed, just make sure you have our standard corporate Linux install" lets those scripts be used by many different teams.
Some things require mountains of code, but not all of them.
Our client side story isn't so good, as your reply predicts. Our primary JS websocket client uses introspection so that's no burden. But we also ship a manually constructed matching Typescript interface which does get out of sync. And other clients are left out on their own. It'd be nice if the codegen tools linked in the original post were further along as this would make life for generic clients much easier. I've been watching them for some years but they don't seem to be going anywhere and I'm comfortable enough with our custom implementation.
being able to easily introspect requests and define your own over the wire was immensely helpful, and it’s painful that i have to reach for a special tool like grpcurl.
If you want, there are plenty of JSON proxies including Cloud Endpoints [1]. I also do most things with manual curl'ing, and relied on the Google APIs to have these kinds of "Fine, we'll also take JSON" setups in place.
Once you've figured it out, you build the proto in your automation directly. But I basically never use grpcurl either.
[1] https://cloud.google.com/endpoints/docs/grpc/transcoding
If you're doing URL routing, you're at the mercy of your web framework
If you've got a data structure coming in, you're probably turning it into types in the programming language you used fast, and you're more quickly into the land of plain old programming, rather than routing configuration in a web framework.