blitz-js / superjson

Safely serialize JavaScript expressions to a superset of JSON, which includes Dates, BigInts, and more.
MIT License
3.88k stars 83 forks source link

Question about Rust support #277

Closed Ziothh closed 6 months ago

Ziothh commented 7 months ago

Does there exist a crate that can serialize superjson from and to serde-rs structs?

Correct me if I'm wrong, but the next.js swc plugin just acts as a bridge between 2 node processes/modules right?

Skn0tt commented 7 months ago

Hi @Ziothh! I'm not aware of any crate to do that, no. The SWC plugin is more of a compiler extension that injects SuperJSON calls into a Next.js app during compile-time - it doesn't perform any de/serialisation in Rust.

SuperJSON is built to serialize exactly the data types that exist within Javascript. Other languages have different datatypes, and any conversion between the two will always be messy. So I don't think a JS/Rust interop would be super useful.

What's your usecase for this, and what other solutions have you looked at?

Ziothh commented 7 months ago

Hi @Skn0tt, thanks for the quick answer.

I came across this issue on prisma-client-rust, where a query returns an i64 (BigInt in js) and gets passed to rspc (like tRPC but for js client <-> rust server).

BigInt can't be serialized to JSON, as you guys well know, so I was thinking about making a PR to rspc to add transformer support like tRPC.

I think it would be useful if rust servers and js clients could communicate with SuperJSON. Some examples:

js     <->  rust
BigInt <->  i64
Date   <->  chrono::DateTime
Map    <->  std::collections::HashMap

As a cherry on top specta could then add support for these types to be generated for an even more seamless integration between the two languages.

Skn0tt commented 7 months ago

That sounds interesting! There’s no such package currently. If you want to write one, i’m happy to assist.

There’s two main challenges I see with it, that will probably need solving:

  1. The output format of SuperJSON isn’t subject to semver. This is because we’re expecting the serialising and deserialising ends of a transport to always be on the same version of SuperJSON. I’m not expecting any major changes to the output format, but if they occur, there might be an unexpected version mismatch with the Rust library. We could solve this by putting the output format into a spec, and putting it under Semver - but I’m have to think a bit about the implications before doing that.
  2. The output format is designed to work well in the dynamically-typed world of JavaScript. I don’t know nearly enough about Rust to be certain on this, but I could see that library logic to be kind or hard to write in such a strongly-typed language!

According to the docs, rspc already has a code-processing step. My gut feeling is that it might be easier to have RSPC generate an API client that contains all the JS <-> RS conversion needed for the specific RPC calls, as opposed to writing a SuperJSON adapter.

Ziothh commented 6 months ago

I'm definitely down to write the package/crate but I'm a bit busy right now. After some research I found out that it's not trivial to translate the SuperJSON spec to serde so that's going to be fun.

  1. This one is up to you guys. If you'd switch to semver, I could match my crates version with it but it's not a deal breaker for me.
  2. It's not ideal for rust but I like the custom Recipes feature and don't want to needlessly make a SuperJSON clone.

My gut feeling is that it might be easier to have RSPC generate an API client that contains all the JS <-> RS conversion needed for the specific RPC calls, ... This is true but I'd like the crate to also be standalone to generate JSON files a be usable in API frameworks like axum.

I'll close this for now and I'll hit you up if I need your assistance :). Thanks for the help!