by carderne on 8/20/24, 10:31 AM with 3 comments
The biggest downside (imo) of the Stripe approach is that you either have to store them as strings, which isn't great, or strip/prepend in your API layer.
So I made a new thing called UPID. It's most similar to ULID, as it includes a time-component (but with lower precision) and also encodes to a base32 alphabet. But it also includes a 20-bit prefix (allowing four characters). So it can be stored as a UUID or anywhere a 128-bit blob goes, and it always knows what its prefix is because it's baked in.
I've made implementations for Python, Rust and TypeScript, as well as a Postgres extension (with a upid datatype). Mentioned it a few weeks ago in a HN discussion and people seemed pretty interested so thought I'd post it as a submission.
In Rust it looks like this:
use upid::Upid;
Upid::new("post"); // post_2acqyme2ygscyguveuhj5a
There are more examples in the repositories.Repo (Python, Rust, Postgres): https://github.com/carderne/upid
TypeScript: https://github.com/carderne/upid-ts
Demo site: https://upid.rdrn.me/
by nivertech on 8/20/24, 12:03 PM
UPID is as UPID does
---
BTW: Hi/Lo scheme for Primary Keys / IDs was invented long before Stripe existed. Partcularly, I used short up to 3 letters prefixes to make IDs Human-readable (and writable!) more than 20 years ago. 5 years later Amazon started using similar scheme in their AWS product, i.e i-NNNNN for instances, etc.[1].
In theory there are 2 kinds of ID schemes: technical/surrogate and natural/business/semantic (i.e. those derived from the natural properties of the object the ID refers to).
Adding a prefix with the type, makes ID scheme hybrid. "Hi" part (prefix) is natural, and "Lo" part is technical. In case of UPID/ULID/UUIDv7 even the "Lo" part is hybrid, since it includes an information when the entity was created (or at least inserted into the database/system).
---
[1] List of some AWS ID prefixes:
i-
vol-
snap-
ami-
eni-
sg-
vpc-
subnet-
acl-
rtb-
igw-
dopt-
vpn-
vgw-
cgw-
nat-
rds-
lb-