by secure on 12/16/24, 8:18 PM with 212 comments
by dpeckett on 12/16/24, 10:16 PM
Been increasingly using LSP style JSON-RPC 2.0, sure it's got it's quirks and is far from the most wire/marshaling efficient approach but JSON codecs are ubiquitous and JSON-RPC is trivial to implement. In-fact I recently even wrote a stack allocated, server implementation for microcontrollers in Rust https://github.com/OpenPSG/embedded-jsonrpc.
Varlink (https://varlink.org/) is another interesting approach, there's reasons why they didn't implement the full JSON-RPC spec but their IDL is pretty interesting.
by kyrra on 12/16/24, 9:09 PM
The Go OpenAPI did not do this. For many primative types, it was fine. But for protobuf maps, you had to check if the map had been initialized yet in Go code before accessing it. Meaning, with the Opaque API, you can start just adding items to a proto map in Go code without thinking about initialization. (as the Opaque impl will init the map for you).
This is honestly something I wish Go itself would do. Allowing for nil maps in Go is such a footgun.
by parhamn on 12/17/24, 12:07 AM
For most of my projects, I use a web-framework I built on protobuf over the years but slowly got rid of a lot of the protobufy bits (besides the type + method declarations) and just switched to JSON as the wire format. http2, trailing headers, gigantic multi-MB files of getters, setters and embedded binary representations of the schemas, weird import behaviors, no wire error types, etc were too annoying.
Almost every project I've tracked that tries to solve the declarative schema problem seems to slowly die. Its a tough problem an opinionated one (what to do with enums? sum types? defaults? etc). Anyone know of any good ones that are chugging along? OpenAPI is too resty and JSONSchema doesn't seem to care about RPC.
by jeffbee on 12/16/24, 8:58 PM
What I'd like is to rewind the time machine and undo all the path-dependent brain damage.
by the_gipsy on 12/17/24, 9:20 AM
> syntax = "proto3" used implicit presence by default (where cases 2 and 3 cannot be distinguished and are both represented by an empty string), but was later extended to allow opting into explicit presence with the optional keyword
> edition = "2023", the successor to both proto2 and proto3, uses explicit presence by default
The root of the problem seems to be go's zero-values. It's like putting makeup on a pig, your get rid of null-panics, but the null-ish values are still everywhere, you just have bad data creeping into every last corner of your code. There is no amount of validation that can fix the lack of decoding errors. And it's not runtime errors instead of compile-time errors, which can be kept in check with unit tests to some degree. It's just bad data and defaulting to carry on no matter what, like PHP back in the day.
by kubb on 12/16/24, 8:43 PM
by remram on 12/17/24, 4:13 PM
I call this Battlefield versioning, after the Battlefield video game series [1]. I bet the next version will be proto V.
[1]: in order: 1942, 2, 2142, 3, 4, 1, V, 2042
by matrix87 on 12/17/24, 2:11 AM
Glad to see this change, for that use case it would've been perfect
by h4ch1 on 12/17/24, 9:02 AM
Currently I'm not quite sold on RPC since the performance benefits seem to show up on a much larger scale than what I am aiming for, so I'm using a proto schema to define my types and using protoc codegen to generate only JSON marshaling/unmarshaling + types for my golang backed and typescript frontend, with JSON transferred between the two using REST endpoints.
Seems to give me good typesafety along with 0 headache in serializing/deserializing after transport.
One thing I also wanted to do was generate SQL schemas from my proto definitions or SQL migrations but haven't found a tool to do so yet, might end up making one.
Would love to know if any HN folk have ideas/critique regarding this approach.
by favflam on 12/17/24, 6:53 AM
by cyberax on 12/16/24, 11:20 PM
Now you can not use normal Go struct initialization and you'll have to write reams of Set calls.
by tonymet on 12/16/24, 10:25 PM
Lots of teams creating rest / json APIs, but very few who use code generation to provide compile-time protection.
by alakra on 12/16/24, 8:48 PM
by neonsunset on 12/16/24, 11:53 PM
by g0ld3nrati0 on 12/16/24, 10:51 PM
by strawhatguy on 12/16/24, 8:50 PM
A given struct is probably faster for protobuf parsing in the new layout, but the complexity of the code probably increases, and I can see this complexity easily negating these gains.
by tuetuopay on 12/17/24, 1:15 AM
However I can get behind it for the lazy decoding which seems nice, though I doubt its actual usefulness for serious software (tm). As someone else already mentioned, an actual serious api (tm) will have business-scope types to uncouple the api definition from the implementation. And that’s how you keep sane as soon as you have to support multiple versions of the api.
Also, a lot of the benefits mentioned for footgun reductions smell like workarounds for the language shortcomings. Memory address comparisons, accidental pointer sharing and mutability, enums, optional handling, etc are already solved problems and where something like rust shines. (Disclaimer: I run several grpc apis written in rust in prod)
by Naru41 on 12/17/24, 4:39 AM
by cyberax on 12/16/24, 11:45 PM
This one small change can result in an order of magnitude improvement.
by abtinf on 12/17/24, 4:38 AM
I certainly won’t allow this to be used by the engineering teams under me.
by lakomen on 12/16/24, 10:26 PM