22 ms·
Parsing makes it hard. Consider writing an HTTP based RPC server. I parse the first line. It tells me the location and the method. Followed by a bunch of key v
by djha-skin 4y ago
Parsing makes it hard.
Consider writing an HTTP based RPC server. I parse the first line. It tells me the location and the method. Followed by a bunch of key value pair headers where both the key and the value are strings. So far so good, I could write all of the above in C or Go pretty easily. Finally comes the body. I can unmarshall this in Go or parse this in C easily because I can I know what to expect in the body by the time I get there. This is because I already know the method and location.
Contrast this with JSON RPC. I have to partially parse the entire object before I know what function is being called. Only then can I fully parse the arguments because I don't know what type they are (or in other words, which struct the arguments correspond to) until I know what function is being called, what version of RPC is being used, etc.
Super annoying. And HTTP is just sitting there waiting to be used.
HTTP allows for incremental parsing. I can parse the first few lines separately from the body. It makes handling input really nice.
Having everything in a single JSON object doesn't allow for incremental parsing because the standard says I can't guarantee order of key value pairs when an object is concerned.
- Scaevolus 4y agoDistinct RPCs being distinct URLs also makes it possible to easily route and load balance RPCs to different backends, which is lovely for scaling up.
- throwawaymaths 4y agoAt that point you're doing OpenAPI, which will dispense with the subject routing boilerplate of JSON rpc, and have a lighter payload that you have to do less work to understand (presumably the JSON schemas are similar to your db tables)
- jacobsimon 4y agoWhen I’ve considered JSON-RPC in the past, the lack of easily identifiable URLs was the main drawback in my mind due to the difficulty of testing and debugging—the same reason I would never use gRPC or similar on my own projects. That said, I think a well-made browser extension would fix this issue for most people, similar to GraphQL, but it still introduces friction that isn’t immediately beneficial. I’d still give it a try in the future!
- Scaevolus 4y agogRPC actually does have easily identifiable URLs. Protobufs can be heavyweight, but it's trivial to use a different encoding like JSON.
- dahfizz 4y agoWhat do you mean by heavyweight? protobufs should be much faster to work with than JSON.
- SomeCallMeTim 4y agoNot the OP, but: Protobufs are much more complicated on the implementation side than JSON. You at minimum need a protobuf library and a spec for your data that's shared on client and server. Migrations are also a lot more work because you may need to keep around every version of your protobuf in every client and/or server, depending on how synchronized the two are (i.e., if you can guarantee all clients and servers are upgraded 100% synchronously, as on a web site, then it's not so bad, but if clients are apps or peers that may or may not be upgraded, then the server may need to speak many different versions of a protobuf). These all qualify as "more heavyweight," at least from an implementation perspective.
- yencabulator 4y ago> because you may need to keep around every version of your protobuf in every client and/or server That shouldn't be necessary. Protobuf changes are supposed to be additions-only, where existing field numbers never change their meaning, but new optional/default fields are added. If you do that, you only need one version of the proto spec.
- jacobsimon 4y agoI stand corrected!
- mike_d 4y agoJSON RPC tends to embed credentials into the body, where REST puts them in the URL string or headers. This gives you the advantage of load balancers being able to fast drop misbehaving clients for load shedding. You also have the security advantage of authenticating a legitimate client before handing off the payload to a parser (both as a DoS vector, or the risk of parsing untrusted data).
- RedShift1 4y ago> JSON RPC tends to embed credentials into the body, where REST puts them in the URL string or headers. The JSON RPC spec says nothing about authentication, you can use whatever authentication method you wish.
- silvestrov 4y agoMany people have learned the hard way that it is one thing what the spec says, another what software actually do. This is a variation of Hyrum's Law: With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody. https://www.hyrumslaw.com https://www.hyrumslaw.com
- nsteel 4y ago> JSON RPC tends to embed credentials into the body Really? For a JSON-RPC over HTTP API? Where? If you are using a generic JSON-RPC framework (does that exist?) which supports multiple transports then credentials in the request object seems like a good optional feature but surely you could disable it and stick your regular HTTP auth middleware in front?
- pshirshov 4y agoJSON-like data structures do not necessary require a stack automaton for parsing. Moreover they don't necessarily require any parsing at all. E.g. I've implemented a simple indexed binary format for JSON-like data: https://github.com/7mind/sick https://github.com/7mind/sick The problems with JSON-RPC are mostly in its design, it's not ergonomic and its type system is a joke. There are many better alternatives ranging from gRPC (still not ergonomic and not modular) to Protoforce (extremely powerful and ergonomic but only marginally adopted).
- jlokier 4y agoIt's not that parsing JSON to a JSON-like data structure is hard. That's easy. It's the overhead of having to parse it to a generic JSON-like data structure at all, before knowing what the keys and values mean, so you can then transform the JSON-like data structure to the program's API structs. If you knew the shape of the RPC method before parsing the JSON body, the body would be parsed directly to target language structs and variables, without using any generic key-value objects (dicts/hashes/maps), any generic arrays, or even any strings in some cases (when JSON strings represent enums). For many RPCs there would be no memory allocations during JSON body parsing. But you don't know the shape, so you either have to allocate memory and store the input in key-value objects, arrays and strings temporarily, or parse the JSON body in two passes, the first pass to get the shape for the second pass.
- pshirshov 4y ago> It's the cumbersome overhead of having to parse it to a generic JSON-like data structure at all, You don't have to do that. > If you knew the shape of the RPC method The whole idea of RPC is about "knowing the shape" (typing) and good RPC implementations do that. > you either have to allocate memory and store the input in key-value objects If I use JSON-like data structures I don't have to use classic parsers with intermediate AST representations. > or parse the JSON body in two passes I've shown you a small library which allows me not to parse anything at all.
- jlokier 4y ago
- giantrobot 4y agoNot to mention with the HTTP based RPC you can get some contextual freebies with the call like a token in a header and/or cookies. You can use all of that before parsing a single byte of the JSON.
- beached_whale 4y agoI would call it a bug if the client does not send the “jsonrpc” and “method” params first. It’s legal, but stupid. And from there, I know how what I am expecting to be sent and what types they are. If the client sends them out of that order, they get a slower response. But even then, it’s probably still maxing out a GB link.
- justsomeuser 4y agoI do not think "JSON does not support incremental parsing, HTTP does" is the reason why JSON-RPC is less popular. Most typed languages give you two options for parsing JSON: - 1. General JSON values (hash maps of JSON scalar values). - 2. Strongly typed - convert JSON string to a specific type that you defined in your application code. You could use 1 to then use in a switch statement to branch to 2. You may have to parse the JSON twice in some languages to do this, but JSON is typically small and fast to parse.
- FeepingCreature 4y agoSee also my post: You Are Doing JSON-APIs Wrong https://news.ycombinator.com/item?id=31258658 https://news.ycombinator.com/item?id=31258658 JSON can be parsed linearly so long as every key fully determines the format of the value.
- kelnos 4y agoCan be, sure. But in practice that's not very useful: 1. Client libraries may not send keys in a defined order, so the key that tells the server what method to call might end up in the middle or end of the payload. 2. The vast majority of default or common JSON parsers out there for the various languages and frameworks most people use just don't support incremental parsing. Your post isn't particularly relevant, since it proscribes a different way of structuring your payloads than JSON-RPC (and others). It doesn't matter if these others are "wrong"; they exist, and have wide support, so people will gravitate to them, rather than rolling their own.
- FeepingCreature 4y agoI'm aware! My faint hope is if I spread the word, maybe JSON-RPC 2 will not be bad in this way.
- born-jre 4y agoone way could be you peek method using sth like https://github.com/tidwall/gjson https://github.com/tidwall/gjson
- websap 4y agoOther than the alternatives mentioned here, one can also use well known headers that define API Methods which you can use for routing. No need to parse the entire request body just for routing.
- asim 4y agoSo funny you say this. I think it's the insight of many developers including my own. I hacked together a framework that did this before the existence of GRPC. Now I'm trying to formalise it as a protocol. https://github.com/micro/network/blob/main/PROTOCOL.md https://github.com/micro/network/blob/main/PROTOCOL.md
- Matthias247 4y agoI don’t think this matters at all. People usually are not writing their own http libraries. They use existing ones, and those already take care of reading the http headers and the body separately. One should avoid handwriting a http server for avoiding security issues and to benefit from performance gains - eg using http/2. Once one had the body - which will typically be read in one go for usual RPC use cases - it’s as easy to deserialize json as anything else that could be transferred there.
- mattwarren987 4y agoThen again, wouldn't you like the libraries you rely on to have clean simple implemenatations and the people who maintain them as easy a time as possible in doing so?
- touisteur 4y agoIIRC simdjson has some form of lazy parsing. I'm myself more for binary blobs lazily parsed, using a proved language and model checker (like recordflux or recent F* work on safe parsers). You could add a layer to 'optimize' the binary layout to have the most important fields upfront (for partial parsing performance) and everything cleverly aligned in cache lines. You could probably combine it with a partial (proved) HTTP parser and get max efficiency (at the cost of abstraction-breaking layer fusion...).