Using a RegEx to create a UUID string

Posted on

Problem

I’m writing a Discord bot that sometimes requires a Minecraft account UUID to be looked up so this is the function (and MWE) I have written to do this.

'use strict';

const axios = require('axios');

const EDITION = {
    JAVA: 0,
    BEDROCK: 1,
};

async function getUuid(username, edition) {
    try {
        const result = (edition === EDITION.JAVA)
            ? await axios.get(`https://playerdb.co/api/player/minecraft/${username}`)
            : await axios.get(`https://playerdb.co/api/player/xbox/${username}`);

        const player = result.data.data.player;
        if (player !== undefined) {
            return (edition === EDITION.JAVA)
                ? player.id
                : parseInt(player.id)
                    .toString(16)
                    .padStart(32, '0')
                    .replace(/(w{8})(w{4})(w{4})(w{4})(w{12})/, '$1-$2-$3-$4-$5');
        }
        return null;
    }
    catch (error) {
        console.error(`Failed to lookup UUID. Reason: ${error.message}`);
        return null;
    }
}

(async () => {
    console.log(await getUuid('somename', EDITION.JAVA));
    console.log(await getUuid('somename1234', EDITION.BEDROCK));
})();

My concern is with the way that I return a Bedrock UUID using str.replace(regexp, newSubstr) I feel like a more efficient RegEx could be used here but I’m unsure how to write it.

Of course, if there’s anything else wrong this code, I’d like to know, I’m still rather new to using Node.js.

Solution

A general rule to follow when it comes to conditionals is to pull out the one thing that’s actually different. In your case, it’s really just a segment of the URL. The rest remained the same. So instead, ternary that instead.

const service = edition === EDITION.JAVA ? 'minecraft' : 'xbox'
const result = await axios.get(`https://playerdb.co/api/player/${service}/${username}`)

Same applies to your UUID logic. Splinter off the UUID generating piece into its own function. That way, should this piece of code change implementation, you’re not touching the rest of your code. This simplifies your ternary into something like the following:

const player = result.data.data.player
return player === undefined 
  ? null
  : edition === EDITION.JAVA
    ? player.id
    : getUuidFromPlayerId(player.id)

// Then outside getUuid(), define this function.
const getUuidFromPlayerId = id => parseInt(id)
  .toString(16)
  .padStart(32, '0')
  .replace(/(w{8})(w{4})(w{4})(w{4})(w{12})/, '$1-$2-$3-$4-$5')

I wouldn’t worry too much about the regex performance. At this scale, HTTP request latency is probably the bigger concern here, both between your bot and playerdb, and between your bot and Discord. Also watch out for rate limits, services may throttle or outright block your requests if you do them too fast. Make sure your code handles this gracefully.

Also, if you have Node.js 18, native fetch() is available, which removes the need for axios to do HTTP requests.

Leave a Reply

Your email address will not be published. Required fields are marked *