Last week, I built a web app that filters GitHub’s list of public APIs. At first, I just wanted to show the entries on the list that didn’t require any authentication, but it was easy enough to include filtering by all the authentication types, so I ended up doing that as well.
For the software development course I’m taking at Flatiron School, we were tasked with building a single page web app that would use an API and allow some degree of user interactivity. My instructors provided the GitHub public API list, and as I was looking at it, I saw Best Buy had a public API. I signed up for it and messed around with it a little bit, and thought it would be pretty neat to build a little app that showed which RTX 3000 series cards were in stock. If you’re into PC gaming, you’re probably aware of how difficult it is to find them right now.
Building the App
Per my instructor’s suggestion, I began work on the project with an outline that divided the feature list into “MVP” (minimum viable product) and “Stretch” features, do be developed after MVP was reached and a submittable project was finished. For the GitHub Public API List Filterer, the MVP was simply displaying the list of APIs, and being able to sort by each authentication type.
For the APIs documented on the GitHub list, there are 4 types of authentication types: API key, OAuth, X-Mashape-Key, and User Agent (and no authentication, of course). There are four entries for X-Mashape-Key, and one for User Agent, so I decided to just combine those under the “Other” category. This left me with 5 filter buttons: All, API key, OAuth, and Other. The API lets you request the APIs by auth type, but as far as I could tell, only one at a time. I really didn’t want to have a button that returned 4 matches, and another button that returned just one. I also didn’t seem right to make a request one type, append that, then request another and append that with one button press. For that reason, and because I thought the API was a little slow, I decided to just grab the entire list one time, when the website is first loaded, and then do the filtering myself.
So, under the hood, the app fetches the entire list of APIs, and adds them to an array. To show the “All” filter, I just take each entry in that array, turn it into a table row element, and add that table row to the table waiting for it in the DOM. When you select a filter, the full array is then filtered by your selection into a “working” array (so that I can keep the whole list without fetching it again), and the process of adding it the DOM is the same, just instead using the working array.
The “All” filter was very straight-forward. Just append the full list to the DOM. API key and OAuth required just a simple check of a key:value pair, and then returning just the matching APIs, and then appending those to the DOM. For the Other button, I had to check if the auth was X-Mashape-Key OR User-Agent. Scary! Filtering the list ended up being very easy. But I did notice that my website was very slow and unresponsive when going between the filters.
At first, I thought the issue was filtering an array of about 750 objects. I added some console logs to each step of the filtering to be sure where the lag was coming from. It turned out, the issue was actually appending ~750, or ~350 table rows to the DOM at one time. Pagination (something the API did not offer) was on my list of stretch goals, but it was at the bottom of the list, behind searching by name and words in the description, filtering by category of API (animals, finance, shopping, etc), and filtering by APIs that use HTTP or HTTPS. However, locking up the browser so bad that you’re still stuck with the pointer cursor after clicking a button was completely unacceptable to me. Even though the website technically worked and met MVP, I was unhappy with it. After finishing the CSS up, I decided to implement pagination immediately.
Pagination revolves around this code:
It took me a minute to figure out the math for that (it’s never been my strong suit), but once I did, it was pretty easy to finish the feature up. Now instead of just appending the working array, the app instead takes the first 20 entries and adds them to a “paged” array. Then, the app appends those 20 rows to the DOM. It’s much faster. When you hit the next page button, the it calls the .slice method on the working array, and gets the next 20 APIs in the list, and appends those. The back button decrements the pageNumber variable, and gets the previous 20 entries. Of course the app checks to make sure you don’t try to return negative entries when going back, and stops pagination at the end when going forward.
Obviously, there’s still improvements that can be made. For instance, a search bar seems like a pretty good idea. I actually have one in development, but didn’t finish it in time to submit it for the project. There’s also some styling improvements I’d like to make, especially to the table. There’s definitely room for this project to grow. I look forward to refining it in the future.