SETTING UP A BASIC API: PART 2

  

We set up the basic server, but it doesn't really do anything that you can't easily already do with the default StreamElements commands. Yet. Let's create a 'you'll need a custom API for that' command. 

Some experience with JavaScript will help, but isn't required. 

How do we send information to our API routes?

You will notice that some websites have dedicated names in the routes such as the StreamElements chat stats pages: https://stats.streamelements.com/c/pjonp. Having my username at the end of that link tells the server to look up my information. It is a "parameter" and one way to pass information to the server. The other way is using "queries" which you have seen many times when people post absurdly long links that have a ? then a bunch of &= in them. Using queries is very useful, such as a youtube link: https://www.youtube.com/watch?v=XgfswUlk9HU&t=103s The v= defines the video to play and the t= is where to start. 


Example parameter and query routes

Building off of part 1, lets added a couple routes. One using a parameter and one with a query. 

Add this code after the first route we created:
  1. //***Route 2a: This is a PARAMETER test; it will respond with "Hey PARAMETER: {{USER}}"
    app.get('/api/hey/:user', (req, res) => { //.../api/hey/...
      const user = req.params.user;
      const message = `Hey PARAMETER: ${user}`; 
      res.send(message);
    });
    //***



At the end of our api link we have /:user. When we go to our server link at the /api/hey/USER the server will get the USER from the link. In our code we use the req.params to read the input. From our route we are looking for :user so our req.params.user will be the USER and we save that as a variable.

Give it a try (replace my server link with yours):
https://bouncyartisticportablesoftware.pjonp.repl.co/api/hey/TESTUSERNAME



Using a parameter is useful if you want to get information about something that is specific. Like in the SE chat stats example above, getting the stats for a specific user. The other way to pass information into the server is using queries.

Let's add a query route:

  1. //***Route 2b: This is a QUERY test; it will respond with "Hey QUERY: {{USER}}"
    app.get('/api/hey', (req, res) => { //.../api/hey?user=...
      const user = req.query.user;
      const message = `Hey QUERY: ${user}`;
      res.send(message);
    });
    //***




This time at the end of our api link we have ?user=. When we go to our server link at the /api/hey?user=USERNAME we pass along USERNAME as the user query. In our code we use the req.query this time to read the input. We take the req.params.user and save that as a variable.

Give it a try (replace my server link with yours):
https://bouncyartisticportablesoftware.pjonp.repl.co/api/hey?user=TESTNAME



We get the same result as before. Queries are great for sending requests that can have multiple options or inputs. The difference between the two are outside the scope of this project. In my (limited) experience using queries are the best for the projects we are going to do.

Going forward, we will only be using queries. But, when you eventually start setting up more complex projects and databases, I would suggest revisiting the option of including parameters into the mix.

So now that we have a basic understanding of the inputs, go ahead and delete both the 2a and 2b routes we just made 😀


Making the first "complex" command

So far all we have done is basic set up and understanding of an API and getting information to it. Which is nice, but you are here to make stuff. Let's use what we know so far and create a commonly requested command that normally gets the 'you'll need a custom API for that' response.

Our goal is to make a command !hey USER command, but with custom responses based on the user that sends it or is mentioned. 

CODE WARNING!

With our 2a and 2b route removed; let's add a route 2. Hold up on the copy-paste for a minute.

  1. //***Route 2: This is a QUERY route; it will respond with "Hey {{USER}}" depending on the username sent
    app.get('/api/hey', (req, res) => { //.../api/hey?user=...
      const user = req.query.user || ''; //look name after ?user=  OR set to '' if not given
      let message;
      if(user === 'TEST') {
        message = `This is a test username message`;
      } else {
        switch(user.toLowerCase()) { //use lowercase to compare usernames
          case "a":
            message = `Hey A. You're 1st.`;
            break;
          case "b":
            message = `This message is for ${user}`;
            break;
          case "c":
            message = `${user} has it's own message as well`;
            break;
          case "":
            message = `You forgot to add a username to say hey to.`;
           break;
          default:
            message = `Hey ${user}`;
        };
      };
      res.send(message);
    });
    //***

Let's walk through this code real quick to see what is going on.
First we are setting up the route (same as we've done 3 times now) at LINK/api/hey.
Next line we are looking for the query that we send in that is called user and saving that as a const variable with the same name user. You will notice that after the req.query.user there is || '';. If you are not familiar with Javascript the || means "OR", so this is incase there no username provided it will set the user variable to empty. The const form of the variable means that it can not be changed.
After that we set an empty message variable with let. Using let allows us to change it later on, which we will need because that is going to be the message that the bot sends and will depend on the user that used the command or was targeted.
Now comes the normal JavaScript that is often seen and used; the IF/ELSE. If user equals TEST then we set the message to "This is a test username message". Again, if you are unfamiliar with JS you'll notice that there are 3 ='s in a row. We use these to compare and get a TRUE or FALSE back. It's very unlikely, but if the Twitch user with the name TEST uses this command in your chat they would get this message 🤣

Next, we move into the ELSE of our IF/ELSE.

Depending on your experience with JS you have used or seen a complex and lengthy IF/ELSE IF/ELSE change. That of course will work here as well and you can chain else if(user === 'EXAMPLE') { here if that is what is best for you. To save some room on this page and in the code I switched to a switch.

The first thing we want to do whenever we deal with comparing usernames is convert them all to lowercase. If you've already dealt with them then you know why, if you haven't then you will eventually.

Then the code moves into the switches. For example if the user is A (lowercased to a) we set the message for A. message = `Hey A. You're 1st.`; sets the server/bot message (using a single = to set the variable).

We also set response for B & C. That empty String we made in the first step, "", is also set to remind us that we made a mistake 😅

Default at the end of the switch is for any user not in the list.

At this point we have covered all possibilities. A, B, C (& TEST) each have a custom response and all others get the default message.

The final line is the server response with the message we defined.

Depending on your level of JS experience that may seem very complicated or very over written. If you are comfortable using a bunch of IF/ELSEIFs then use those. If you are experienced and want to make it as compact as possible, then go for it with something like:

  1. app.get('/api/hey', (req, res) => { //.../api/hey?user=...
      const user = req.query.user || '';
      const message = ({
        '': `You forgot to add a username to say hey to.`,
        'a': `Hey A. You're 1st.`,
        'b': `This message is for ${user}`,
        'c': `${user} has it's own message as well`,
      })[user.toLowerCase()] || `Hey ${user}`; // || means 'or'. Send the message for the user in the list OR send the default message.
      res.send(message);
    });

Use whatever code style that works best for you. The great part about JS is there are many ways to get the same result, so use the code style that is easiest for you to read and edit.

I personally use a mixture of the 2 above and the most natural for me is:
//***Route 2: This is a QUERY route; it will respond with "Hey {{USER}}" depending on the username sent
app.get('/api/hey', (req, res) => { //.../api/hey?user=...
  const user = req.query.user || ''; //look name after ?user=  OR set to '' if not given
  let message;
  const customMessages = { //use lowercase for usernames
      '': `You forgot to add a username to say hey to.`,
      'a': `Hey A. You're 1st.`,
      'b': `This message is for ${user}`,
      'c': `${user} has it's own message as well`,
    };
  if(!customMessages[user.toLowerCase()]) message = `Hey ${user}` //use lowercase for usernames
  else message = customMessages[user.toLowerCase()];
  res.send(message);
});
//***

All three code blocks above have the same result. Pick one and paste that into your server, it's time to test. Click the STOP button then restart your server.



Setting up the chat command using StreamElements


Back to the custom commands, under chat bot -> chat commands -> custom commands. (https://streamelements.com/dashboard/bot/commands/custom)

Again, click the Add New Command button and set the command name to hey
Response:
  1. $(customapi.https://bouncyartisticportablesoftware.pjonp.repl.co/api/hey?user=${touser})

We are using the ${touser} variable provided from SE, for a list of all variables see: https://streamelements.com/dashboard/bot/command-variables

Click the SAVE button then load up your stream chat (https://www.twitch.tv/popout/USERNAME/chat) and give it a try!



We set up a complex custom response bot command using our API and it works perfectly!

Oh; wait, what happened on that last one?

We have a bug in our code because the variable we chose is passing along the @ along with the username.

Let's go back to our server and filter that out. Luckily we can handle that with our first line and format the incoming data how we want 😀.

Update the user definition for our query to:
const user = (req.query.user || '').replace(/[^\w]/g, ''); //look name after ?user= OR set to '' if not given

We are taking the String that we already had and doing a .replace() on it. The first part of the replace /[^\w]/g is Regex, but more in Part 3 for that. It says that anything that is NOT a letter or number needs to replaced with the second part '' (nothing).



Do the STOP and restart thing and test again.


End part 2 😁. 

Comments