I recently worked on a project which needed to interface five hospital systems to one national system. As part of the SOAP submission to the national system I needed to provide a unique UUID which would identify each user from the source hospital system. I wanted to generate the UUID on the fly as the message was being created - so I needed a way to regenerate the same UUID for the same user.
Each hospital system had their own unique user account reference. So by combining this unique account reference with an organisation identifier, I could generate a unique UUID for users with the same account reference across different facilities.
This is the function I came up with.
Updated (11.03.2025)
- Switched from MD5 to XXH3 as suggested by StephaneBunel
- Swiched to Google's UUID package.
func deterministicGUID(organisation string, account string) uuid.UUID {
var hash [16]byte
var guid uuid.UUID
hash = xxh3.HashString128(organisation + account).Bytes()
// uuid.FromBytes returns an error if the slice
// of bytes is not 16 - as hash is defined as
// [16]byte then we can ignore checking the error
guid, _ = uuid.FromBytes(hash[:])
return guid
}
package main
import (
"fmt"
"github.com/google/uuid"
"github.com/zeebo/xxh3"
)
func main() {
fmt.Println("UUID for user 357 @ LTH : ", deterministicGUID("LTH", "357").String())
fmt.Println("UUID for user 5689 @ BHT : ", deterministicGUID("BHT", "5689").String())
}
UUID for user 357 @ LTH : c737ccd9-62da-f7b0-a6ad-6d21573b72e7
UUID for user 5689 @ BHT : 78e67353-64c6-2507-5683-4612bddcfe6f
I had been using this as well and I was wondering when looking back into this yesterday. Why would you go to a string and take a portion of it, instead of taking the []byte array, which is 16 long as expected by uuid.
Resulting in this piece of code: