Using a REST API

REST APIs are extremely popular on the web and allow you to freely grab a site's data if it has an available API over an HTTP connection.

If you've ever seen a music bot that accepts a YouTube query instead of just a video's URL, then you've seen a REST API in action. discord.js uses the Discord API, so you've probably used an API yourself.

Making HTTP requests with Node

In these examples, we will be using node-fetchopen in new window, an excellent library for making HTTP requests.

To install node-fetch, run the following command:

npm install node-fetch
1

Skeleton code

To start off, you're just going to be using this skeleton code:

const { Client, Intents, MessageEmbed } = require('discord.js');

const client = new Client({ intents: [Intents.FLAGS.GUILDS] });

client.once('ready', () => {
	console.log('Ready!');
});

client.on('interactionCreate', async interaction => {
	if (!interaction.isCommand()) return;

	const { commandName } = interaction;

	// ...
});

client.login('your-token-goes-here');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

TIP

We're going to take advantage of destructuring in this tutorial to maintain readability.

Using node-fetch

node-fetch is a lightweight, Promise-based module that brings the Fetch APIopen in new window, which is available in browsers, to node. If you aren't already familiar with Promises, you should read up on them here.

In this tutorial, we'll be making a bot with two API-based commands using the random.catopen in new window and Urban Dictionaryopen in new window APIs.

To require node-fetch, you'd do:

const fetch = require('node-fetch');
1

Random Cat

Random cat's API is available at https://aws.random.cat/meow and returns a JSONopen in new window response. To actually fetch data from the API, you're going to do the following:

fetch('https://aws.random.cat/meow').then(response => response.json());
1

It may seem like this does nothing, but what it's doing is launching a request to the random.cat server. The server is returning some JSON that contains a file property, which is a string containing a link to a random cat. node-fetch returns a response object, which we can change into JSON with response.json(). Next, let's implement this into a command. The code should look similar to this:

client.on('interactionCreate', async interaction => {
	// ...
	if (commandName === 'cat') {
		const { file } = await fetch('https://aws.random.cat/meow').then(response => response.json());
		interaction.reply({ files: [file] });
	}
});


 
 
 
 

1
2
3
4
5
6
7

So, here's what's happening in this code:

  1. You're sending a GET request to random.cat.
  2. random.cat sees your request and gets a random file from their database.
  3. random.cat then sends that file's URL as a JSON object that contains a link to the image.
  4. node-fetch receives the response and deserializes it with response.json().
  5. You then send the object's file property in Discord.

WARNING

The response will only be parsed if the server's Content-Type header includes application/json. In some cases you may have to apply the .text() method instead of .json() and JSON.parse() it yourself.

Urban Dictionary

Urban Dictionary's API is available at https://api.urbandictionary.com/v0/define, accepts a term parameter, and returns a JSON response.

First, you're going to need to fetch data from the API. To do this, you'd do:

// ...
client.on('interactionCreate', async interaction => {
	// ...
	if (commandName === 'urban') {
		const term = interaction.options.getString('term');
		const query = new URLSearchParams({ term });

		const { list } = await fetch(`https://api.urbandictionary.com/v0/define?${query}`)
			.then(response => response.json());
	}
});
 



 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11

Here, we use JavaScript's native URLSearchParams classopen in new window to create a query stringopen in new window for the URL so that the Urban Dictionary server can parse it and know what to search.

If you were to do /urban hello world, then the URL would become https://api.urbandictionary.com/v0/define?term=hello%20world since the string gets encoded.

You can get the respective properties from the returned JSON. If you were to view it in your browser, it usually looks like a bunch of mumbo jumbo. If it doesn't, great! If it does, then you should get a JSON formatter/viewer. If you're using Chrome, JSON Formatteropen in new window is one of the more popular extensions. If you're not using Chrome, search for "JSON formatter/viewer <your browser>" and get one.

Now, if you look at the JSON, you can see that it's a list property, which is an array of objects containing various definitions for the term (maximum 10). Something you always want to do when making API-based commands is to handle no results. So, let's throw a random term in there (e.g. njaksdcas) and then look at the response. The list array should then be empty. Now you are ready to start writing!

As explained above, you'll want to check if the API returned any answers for your query, and send back the definition if so:

if (commandName === 'urban') {
	// ...
	if (!list.length) {
		return interaction.reply(`No results found for **${term}**.`);
	}

	interaction.reply(`**${term}**: ${list[0].definition}`);
}


 
 
 

 

1
2
3
4
5
6
7
8

Here, you are only getting the first object from the array of objects called list and grabbing its definition property.

If you've followed the tutorial, you should have something like this:

User used /urban
Guide Bot Bot 06/06/2023
@User, No results for njaksdcas
User used /urban
Guide Bot Bot 06/06/2023
**hello world**: The easiest, and first program any newbie would write. Applies for any language. Also what you would see in the first chapter of most programming books.

Now, let's just make this an embed.

We are also going to be defining a utility function at the top of the file so that the embed doesn't error when the field value is over 1024 characters. Here is a bit of code to do that:

const trim = (str, max) => ((str.length > max) ? `${str.slice(0, max - 3)}...` : str);
1

The following snippet is how to structure the embed:

const [answer] = list;

const embed = new MessageEmbed()
	.setColor('#EFFF00')
	.setTitle(answer.word)
	.setURL(answer.permalink)
	.addFields(
		{ name: 'Definition', value: trim(answer.definition, 1024) },
		{ name: 'Example', value: trim(answer.example, 1024) },
		{ name: 'Rating', value: `${answer.thumbs_up} thumbs up. ${answer.thumbs_down} thumbs down.` },
	);

interaction.reply({ embeds: [embed] });
1
2
3
4
5
6
7
8
9
10
11
12
13

Now, if you do that same command again, you should get this:

User used /urban
Guide Bot Bot 06/06/2023
Definition
The easiest, and first program any newbie would write. Applies for any language. Also what you would see in the first chapter of most programming books.
Example
programming noob: Hey I just attended my first programming lesson earlier!
.NET Veteran: Oh? What can you do?
programming noob: I could make a dialog box pop up which says "Hello World!" !!!
.NET Veteran: lmao.. hey guys! look.. check out this "hello world" programmer

Console.WriteLine("Hello World")
Rating
122 thumbs up.
42 thumbs down.

Resulting code

지금까지 만들어온 코드를 비교해보고 싶으시다면, 이 깃헙 리포지토리 open in new window 에서 확인하실 수 있습니다.