Before we start coding, let’s recap what our project entails:
- Pokemon Number — (No. XXX)
- Height — Ft’ Inches”
- Weight — lbs
- Speak (Voice Functionality)
- Not Found Error Handling
Sweet, now that we know the full scope of our project, let’s start coding.
Let’s start by going over the external services and framework we are going to leverage in this tutorial.
Feel free to spend some time exploring the API to get an idea of what’s available. Also, we will be using an API wrapper for Node.js to allow us to easily interact with the API. Fortunately, PokeAPI provides us with a node-based wrapper called Pokedex-Promise-V2.
Top 4 Bot Tutorials
Discord isn’t a built-in platform, but I’ve created an open-source custom connector called botkit-discord to simplify that piece for you.
This will abstract the configuration and Discord functionality for our tutorial, as well as give us all of the botkit methods a lot of us are familiar with.
Time to Code
First off, let’s clone a Discord starter provided by Glitch.
$ git clone https://github.com/FogCreek/starter-discord.git
This will cut some time on how to prepare and organize your code — and some typical bootstrapping.
Now let’s install our dependencies and add a few additional ( pokedex-promise-v2 @google-cloud/text-to-speech):
$ npm install & npm install pokedex-promise-v2 –save
If we take a look at the repository, we can see the directory structure as following:
Most of these files you won’t be concerned with, but expect to be doing a bit of work within the skills directory.
1. Searching For Pokemon: “!pokedex”
Start by creating a new directory called services, where we will be storing all of our external API code.
$ mkdir services
Within the services directory, create a new file called pokedex.js and add the following code:
Here we are essentially creating a “wrapper” over the SDK to give us flexibility. Thus, if our external API were to ever change, we can just alter this “service” file and never have to touch our core bot logic.
Now we can write our first “skill”, the search functionality.
Create a new file in the skills directory called, "pokedex" with the following code:
🚨 HELP! What’s happening?!
Well in our bot.js code, we are manually calling any file in our skills directory. This is where we can create “hears” handlers for our botkit controller. If you aren’t familiar with the “hears” method, I encourage you to go over the botkit basics to understand how it all works.
Now, let’s create our newest skill:
If you look at the code, we are only telling the bot to “hear” for a “!pokedex” in a message and do something with it. But if the user doesn’t provide something to search with we just provide them a little assistance:
Time to add our search functionality with using our imported service:
Here, we are using our search method that supports number or name lookups, and returning the result to our recipient.
However, if we can’t seem to find a match, we will simply reply with “NO DATA”, just to match the typical Pokédex experience!
Great now we can test this by adding our bot token to the bot.js file within the configuration object.
Once we’ve configured our token, start up our bot locally by running npm start, which will show that your bot is ready to respond once it's been logged in.
Once it’s up and running, let’s message our bot with a few test commands:
- !pokedex 1 – Expect a result
- hello !pokedex 1 – Expect a result
- hello !pokedex 99999 – Expect "NO DATA"
But you know what would be more amazing? If we take it up a notch and show an embedded message to our users to match our high fidelity mock.
So let’s talk about how we can create Discord Rich Embedded Messages.
1.1 Rich Embed
As mentioned in our first part of the tutorial, our embedded message is going to give it more of a realistic Pokédex experience.
If you don’t remember what this looks like, let’s refer to the picture below as a refresher:
Using the Discord rich embed visualizer created by Github user, leovoel, we crafted this experience for our users. On the left side of the image, we can also see how our JSON payload should be sent to Discord for it to render like this.
But wait… is there an easier way to build this JSON in a less error-prone fashion?
This is where the builder pattern comes in handy!
“The Builder is a design pattern designed to provide a flexible solution to various object creation” — Wikipedia
Now don’t worry, we won’t be building our builder pattern for embedded messages because fortunately, Discord.js RichEmbed constructor provides a builder for crafting these embedded messages.
On top of that, discord-botkit passes along this RichEmbed constructor in the package. Thus to utilize it, all you need to do is…
With this constructor, we can easily set fields with helper methods built into the concrete instance such as addField, setColor, etc.
For example, the following code would create this result (from the botkit-discord docs):
Now before we create our embedded Pokédex message, let’s reference the API to see what data is available to populate our required fields:
I prefer to list all the required fields and match them to their corresponding keys for a better visual reference:
- Pokemon Number — (No. XXX) — id
- Sprite/Avatar — sprites.front_default – let's use the default front sprite
- Category — types.type.name – We will grab just the first type for now
- Height (Ft’ Inches”) — height – in decimeter, we will need to convert to inches
- Weight (lbs )— weight – in hectograms, we will need to convert to lb
If you notice the description is missing, don’t worry! It isn’t available from the first request, but I’ll go over how we can update our service to retrieve this as well.
Now we can build our embedded message.
Start by creating the embed message, which we will pull straight from the discord-botkit. Add the following constructor within the .then of your service search call:
Next let’s populate the fields and send it to the response
Now if we put it all together, it should look like this:
Time to validate our progress and re-run our bot with npm start
The Final Touches
Excellent, time for the final touches: description, weight and heights conversions, and capitalizing the name.
For our description, we will need to perform another search called getPokemonSpeciesByName and combine that to our search result.
Let’s go back to our service/pokedex.js file, and merge the getPokemonSpeciesByName method results with our existing code.
Refer to Pokeapi Pokemeon Species to learn more about the structure for
I won’t explain everything that’s happening, as there are many tutorials covering Promise.all, but I provided comments for some context.
We essentially create our own modified search results providing all the key data we need.
Now let’s update our embed with our latest description.
Let’s also format the weight and heights to reflect the good’ol imperial system to match the US Pokédex experience.
Install our helpful library called convert-units:
$ npm install convert-units –save
Add the following functions to your skills file — you can probably figure what’s happening here:
In addition, let’s add one more helper to format the name so that our results have an upper case in the first character of the name.
Now when we put it all together our embed update methods should appear like such:
And after we restart our server, we can finally test our end product, and should have the following response:
Finally we can see all that’s needed to build out the search functionality and how to build out a visual embed message.
Feel free to expand it even further by adding even more additional logic such as different colors based on types (blue for water?), additional attachments for sprites, or even other language supports!
So let’s recap, in this tutorial, we learned the following:
- How to create our first hears handler, !pokedex
- How to use the Pokeapi to return Pokemon results
- How to respond with Discord’s Rich Embed messages
Now, if you are still having troubles with the code, refer to Git repository in the PART_2 branch.
Feel free to check out my other Discord chatbot tutorial: Creating a Magic 8 Ball for Discord in Node.js and Botkit
Stay tuned for the final part of the tutorial, where we go over how to utilize Google’s Text-to-Speech API to create audio functionality for our Pokédex!
Don’t forget to give us your 👏 !