SETTING UP AN API: PART 3 (DATABASE)
Some commands will require storing information and then recalling it later. How would one create a database to do that?
What's the goal?
Part 3 in the building API series will walk through adding a simple database to our server to save information and recall it later. As we work through this example, I'm going to explain how I approach adding code whenever I start a new custom widget/overlay and API call.
As with any project, it all starts with an idea:
WARNING:
Servers should always be private and are not intended to be readable by users!
We are using the free service provided by replit which is great for projects like this but it is not protected when using the free version. For example you can see my full code if you go to my mine: https://replit.com/@pjonp/chatbot-api (and fork it).
This project will include the first "secret" that we need to hide from other people. We need to try our best to prevent them from seeing the link to our server.
I'll come back to this later. For now we want to make sure that any command that uses our server only says ${customapi} on your commands page, https://streamelements.com/YOURNAME/commands
Setting up the database
Before we get into making the route for this project we need to set up a database. This will store the multiTwitch link so the server can read it later and send it to chat.
In the shell copy and paste (right click paste): npm i @replit/database and hit Enter
This will install the server code the next time we do a restart.
Our code needs to initialize the database and start it. Use this code at the top of the index.js server file right after we bring in the Express server:
Adding our multiTwitch route
While it is possible (and better practice) to make 2 separate routes, one to "save" (PUT) the information and a second one to retrieve (GET) it, for this example we will only be using a single GET route to do both. Just remember as you build your own projects that you can (and should) split the routes up between saving and reading.
The first thing I do when creating a new route is to add the basic function and create an outline for what I want to achieve. Let's start with this code for our third route and then fill in the objectives:
This approach helps focus better on the end goal and breaks it down into smaller steps. The first step being to define the route: //.../api/multitwitch?squad=...&ismod=...
We know we want to check 2 pieces of information (Queries); "squad" to make the link from and then check if the command was sent by a user that "ismod".
We set up two variables to match our expected queries: setting squad to match our input, expecting a mod to say !multitwitch user1 user2 user3 and grabbing those usernames to add to our link. (!multitwitch will be removed when we set up the commands in SE). If no usernames are included we set the squad as an empty string "". Then we do a mod check. (mod information is also passed later during command setup).
Then start working through the code objectives.
The first one is pretty straight forward. We can just check if the sender is NOT a mod. Only mods can edit the link so this will always return the link from the database from non-mods.
We can move onto the else for formatting the message if it was sent by a mod and fill in more of the outline:
CODE / OVER-EXPLANATION WARNING:
I fill in all possible outcomes first as the functions at the bottom. The sendMsg function at the bottom will send our response back to chat. There are two possible messages; either get the link that is in the database or put a new one.
The getLink function will read our database, get the existing link and then send it to chat.
Or the saveLink which will put a new link before sending to chat.
Once these are defined, I can fill in the end of line 33, sending all non-mod message straight to getLink()
Otherwise (else) the command is sent by a mod.
I split the squad into each word to determine the squad members that are intended to be in the multiTwitch link.
Since the expected command is !multitwitch user1 user2 user3 and the command !multitwtich was already removed from the command (we'll get to that later), the String "user1 user2 user3" is converted into any Array ['user1','user2','user3'] by using the split() function and separating each one by every space. (' ') on line 36.
Now on line 38, I can check the length. If the mod sent 1 or less users, then I want the response to be the link that is already saved. This prevents a moderator from accidentally clearing the link or trying to create a multiTwitch link with only one username. If you wanted to add the option for your mods to remove or delete the existing multiTwitch link, this would be a good place to check for something such as !multiwitch remove 😀
At this point, the logic has narrowed it down that the moderator must be trying to update the link so saveLink is called on line 40 and I pass along the username Array.
The basic logic for the handling the command is done now, but I still need some more code in the saveLink function to convert ['user1','user2','user3'] into a multitwitch link.
Line 53 is the reverse of the split() from a few lines above. This time I join() the usernames, but instead of having spaces between the usernames, I want /'s. At this point joinUsernames is "user1/user2/user3".
Finally; I take that String and create a multiTwich link: multitwitch.tv/user1/user2/user3
Using the database
Basic logic [x].
Now let's use this database thing.
Our third route should look like this at this point:
Let's set up the saveLink() first.
Using the db.set(KEY, VALUE).then(() => {... format, add this at the end of the function:
If you have used the SE KV Store for widgets before this might look similar. If not, spoiler, it's the same format StreamElements uses for widget databases 😉
We took our data, the multiTwitch link, and saved it as a Key named "multiTwichLink".
Now all we need to do is reverse the process and read the same key using db.get(KEY).then(value => {...
Drop this into the empty getLink function:
We get the value of the muliTwtichLink KEY, then make sure it exists. If there is NO value we force an error. That error is handled by the catch at the end. When there is a value in the database (our link) we send that back for the bot to say in chat. If there is an error, the 'catch' message "no link" is sent instead.
That's it. Our route is complete:
Hit the STOP button on the server then run it again. (Note: this will take a minute as it installs the database package we added at the start).
Setting Up The Commands
Fire up your StreamElements dashboard, we need to add two commands and do some testing.
We need a command for everybody to use to get the muliTwitch link and a command that only moderators can use to set the link.
(Replace your server and name with yours)
First the everybody GET command. (user level: everyone): $(customapi.https://bouncyartisticportablesoftware.pjonp.repl.co/api/multitwitch)
Second the moderator "PUT" (user level: mod): $(customapi.https://BouncyArtisticPortablesoftware.pjonp.repl.co/api/multitwitch?squad=${1:|null}&isMod=true)
The ${1:} is to grab all of the inputs after the the command, so the command "!setmultitwitch" is not sent.
For those taking notes; you'll notice that the isMod isn't really needed (only the mod command will send the "squad" info, it's always null in the everyone command). A goal for this example was to show handling more than query in a single route.
You will also notice that both of these links have the same .../api/multitwitch base link. We used queries for the moderator command to pass in the information to set the link and define the moderator. Generally, you would want to set up 2 different routes with the same base; one to put the information and one to get the information. Since we are making ChatBot commands, they will always be GET requests
You could split split the routes up and move all of the "mod" command logic it's route such as .../api/putmultitwitch
Final note: this is the first 'unsecure' route. Anyone that knows about your link "https://BouncyArtisticPortablesoftware.pjonp.repl.co/api/multitwitch?squad=${1:|null}&isMod=true" can set your link 😬.
You can set my multiTwitch to anything you want.... (seriously, test it 😁)
https://chatbot-api.pjonp.repl.co/api/multitwitch?squad=this link is not secure&isMod=true
Then see the result:
https://chatbot-api.pjonp.repl.co/api/multitwitch
Always be aware that the API server link (just the chatbot-api.pjonp.repl.co part) will allow users to see see your server source code and endpoints! Revisit the the warning at the top of this post and double check that none of your commands include your server link and NEVER post your server link for others to view if you have a route that you don't want any user to be able to use.
[x] Create an API server
[x] Send information to server from chat commands
[x] Set up a database
[ ] Call other APIs with our API ....
Comments
Post a Comment