oxidecomputer / dropshot

expose REST APIs from a Rust program
Apache License 2.0
793 stars 73 forks source link

Make page tokens shorter #923

Open david-crespo opened 4 months ago

david-crespo commented 4 months ago

This is helpful but not essential for https://github.com/oxidecomputer/console/issues/1102, putting page tokens in console URLs. The real blocker is #436.


Page tokens are base64ed JSON and they come out pretty long. Here's an example:

> atob('eyJ2IjoidjEiLCJwYWdlX3N0YXJ0Ijp7InNvcnRfYnkiOiJuYW1lX2FzY2VuZGluZyIsInByb2plY3QiOiJhbGFuIiwibGFzdF9zZWVuIjoienp6LWluc3QtMTE0In19')
'{"v":"v1","page_start":{"sort_by":"name_ascending","project":"alan","last_seen":"zzz-inst-114"}}' 

oxiderack.com/projects/mock-project/instances?page=eyJ2IjoidjEiLCJwYWdlX3N0YXJ0Ijp7InNvcnRfYnkiOiJuYW1lX2FzY2VuZGluZyIsInByb2plY3QiOiJhbGFuIiwibGFzdF9zZWVuIjoienp6LWluc3QtMTE0In19 would work fine I guess, but to me it looks a bit silly. Here's where we do the serialization:

https://github.com/oxidecomputer/dropshot/blob/6b410861c105052faa30536edc9d271b2abf1be7/dropshot/src/pagination.rs#L417-L430

It should be pretty easy to encode the token in a more efficient format like MessagePack and maybe reduce the size of the data itself by, e.g., making some keys shorter.

Method Length of token
Current: base64 JSON string 128
MessagePack JSON as-is 104
MessagePack JSON with page_start -> p 92
MessagePack struct directly with serde_rmp (code below) 52
Rust program to compare base64 JSON and MessagePack ```toml # Cargo.toml [package] name = "serialization-test" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" rmp-serde = "0.15.4" base64 = "0.13.0" ``` ```rs // src/main.rs extern crate base64; extern crate rmp_serde as rmps; extern crate serde; extern crate serde_json; use serde::{Deserialize, Serialize}; use std::error::Error; #[derive(Debug, PartialEq, Deserialize, Serialize)] struct MyStruct { v: String, page_start: PageStart, } #[derive(Debug, PartialEq, Deserialize, Serialize)] struct PageStart { sort_by: String, project: String, last_seen: String, } fn main() -> Result<(), Box> { let data = MyStruct { v: "v1".to_owned(), page_start: PageStart { sort_by: "name_ascending".to_owned(), project: "alan".to_owned(), last_seen: "zzz-inst-114".to_owned(), }, }; // Serialize with JSON let json_data = serde_json::to_vec(&data)?; let encoded_json = base64::encode(&json_data); // Serialize with MessagePack let msgpack_data = rmps::to_vec(&data)?; let encoded_msgpack = base64::encode(&msgpack_data); // Compare the lengths of the encoded strings println!("Base64 JSON Length: {}", encoded_json.len()); println!("Base64 MessagePack Length: {}", encoded_msgpack.len()); Ok(()) } ```
ahl commented 4 months ago

What about compressing the text first?