Code a random person name generator in JavaScript
In this tutorial, we'll create a random name generator. It will generate first and last names, and we'll have the option to specify gender too.
Fetching the data
First, we are going to need some data to work with. This tutorial will use data from randomlists.com, but you could adapt this code to use any data source—you just need each type of name (first, last etc.) as an array of strings.
Here's the data we'll be using (you can click the links to see the raw JSON in your browser):
- Female first names: https://www.randomlists.com/data/names-female.json
- Male first names: https://www.randomlists.com/data/names-male.json
- Last names: https://www.randomlists.com/data/names-surnames.json
Using the Fetch API, let's start by writing an async function to fetch the data:
async function fetchData(url) {
const response = await fetch(url);
return response.json();
}
As this is an async function, let's add some error handling to log an error to the console in case the network request fails:
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
} catch (error) {
console.error('Unable to fetch data:', error);
}
}
This is general-purpose function to fetch JSON, but we actually want to fetch from three different API endpoints (for male first names, female first names, and last names).
Let's write a new function that uses our fetchData
function and the endpoints mentioned above to do this.
Notice how the URLs are the same apart from one word? Rather than write each URL in full, we can use a template literal to make the code less repetitive:
function fetchNames(nameType) {
return fetchData(`https://www.randomlists.com/data/names-${nameType}.json`);
}
This allows us to supply the missing portion of the URL as a variable when we call this function, e.g. fetchNames('male')
.
Picking a random name from the list
Now that we have a way to fetch each list, we need a way to pick a random item. We can do this with a simple helper function:
function pickRandom(list) {
return list[Math.floor(Math.random() * list.length)];
}
Generating a random name
We have all the individual parts of our name generator ready to go. Let's write our final generateName
function. It will take a gender
parameter, which we'll use to determine whether to return a male or female name.
async function generateName(gender) {
try {
// Fetch both name lists in parallel
const response = await Promise.all([
fetchNames(gender),
fetchNames('surnames')
]);
// Promise.all returns an array of responses
// to our two requests, so select them
const [firstNames, lastNames] = response;
// Pick a random name from each list
const firstName = pickRandom(firstNames.data);
const lastName = pickRandom(lastNames.data);
// Use a template literal to format the full name
return `${firstName} ${lastName}`;
} catch(error) {
console.error('Unable to generate name:', error);
}
}
As this is another async function, it will return a promise. To console.log
the result, we can call it like this:
generateName('female').then(console.log);
generateName('male').then(console.log);
Making gender optional
What if we forget to pass the gender
parameter?
Currently, we'd get an error as our program would try to fetch data from a URL that doesn't exist. Oh no! How should we handle this?
We have a couple of options:
- We could throw an error if the
gender
parameter isn't passed - We could pick a random gender
Let's implement option two—we can do this easily with our pickRandom
helper function. The first call to fetchNames
can simply be changed to this:
fetchNames(gender || pickRandom(['male', 'female']))
Now specifying a gender is optional, and our name generator will always return a name either way.
Putting it all together
The full program looks like this:
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
} catch (error) {
console.error('Unable to fetch data:', error);
}
}
function fetchNames(nameType) {
return fetchData(`https://www.randomlists.com/data/names-${nameType}.json`);
}
function pickRandom(list) {
return list[Math.floor(Math.random() * list.length)];
}
async function generateName(gender) {
try {
const response = await Promise.all([
fetchNames(gender || pickRandom(['male', 'female'])),
fetchNames('surnames')
]);
const [firstNames, lastNames] = response;
const firstName = pickRandom(firstNames.data);
const lastName = pickRandom(lastNames.data);
return `${firstName} ${lastName}`;
} catch(error) {
console.error('Unable to generate name:', error);
}
}
Here's a working version you can run:
Using your own data
Want to use a different API? Don't want to pull data from an API at all? You just need to update the fetchNames
function.
Let's say you wanted to hardcode arrays of hobbit names. You could update it to look like this:
function fetchNames(nameType) {
let names = [];
switch (nameType) {
case 'female':
names = ['Berthefried', 'Tatiana', 'Hildeburg'];
break;
case 'male':
names = ['Bilbo', 'Frodo', 'Theodulph'];
break;
case 'surnames':
names = ['Baggins', 'Lightfoot', 'Boulderhill'];
break;
}
return { data: names };
}
If we're working with local data (instead of pulling data from API endpoints), we also need to simplify the generateName
function as it no longer makes any async calls:
function generateName(gender) {
// Fetch the names
const firstNames = fetchNames(gender || pickRandom(['male', 'female']));
const lastNames = fetchNames('surnames');
// Pick a random name from each list
const firstName = pickRandom(firstNames.data);
const lastName = pickRandom(lastNames.data);
// Use a template literal to format the full name
return `${firstName} ${lastName}`;
}
As this version is not async, it does not return a promise, so you can just call it like this:
generateName('female');
generateName('male');
generateName();
And that's it: a random person name generator that you can adapt to work with any data source.
Character names, fantasy names, human names... whatever you want!