Web-Based Query Tool with REST Requests

Initialized 2022.03.09 | Revised 2023.11.16
This Page
Screenshot of the final web tool with the corner peeled up to reveal the Scryfall logo.

This is simple web tool utilizing Scryfall's free API to query cards of value for the popular card game, Magic: The Gathering (often abbreviated with MTG). The finished tool can be found here. Like my personal website, this query tool is a static Vue website hosted off of GitHub Pages.

Unlike my personal site, however, this query tool utilizes REST API calls to the Scryfall database. These are primarily GET requests for either currently known sets in the game or cards that were released in a particular set.

Scryfall logo

Background

"Why sets?" you may be asking. I've had my whole collection organized into sets for years and until recently, I thought that's how they would stay. I had this ambition of having a four copies of every card from each set. While ambitious, it was a reasonable goal for a while, until sets starting coming out with alternate prints and more and more sets were being released every year. I finally realized that what I cared about what not being a completionist, but being able to play whatever deck I wanted. All that meant was having a play set of each oracle card.

That's where this tool comes in. It allows me to pull up any set in Magic's history and determine if the cards printed in them are valued for either their rarity or power in the game. Granted, there's no concrete way of knowing this, but a good estimate can be made based on whether all printings of a card share a similar price or just the printings of a particular set.

Disclaimers

I do have to explicitly mention that the only part of this site that is truly mine is the site logo and over-all construction and design itself. Even the site code was constructed with some assistance from web searches. Even so, this tool was designed for personal use and is only publicly available for ease of use.

Magic: The Gathering, game data, and iconography are copyright Wizards of the Coast LLC, a subsidiary of Hasbro, Inc.

Magic: The Gathering logo
Hasbro logo

Data is collected from the publicly available Scryfall API and is copyright Scryfall, LLC. with no affiliation to this site or the query tool. This service is currently free, so there are delays added into the API requests in an attempt to limit its overuse.

Components

This tool is pretty small, so really there's only a couple of components worth mentioning here. Just a reminder that this is a Vue 3 site, so all the content for a single component appears in the same file.

Set Filter

The set filter was probably the most difficult to set-up. I had a few issues I had to overcome with it. The first is that I wanted to be able to use and see the set icons in the select option list. I'm a visual person, ad seeing that icon is much faster for me than trying to remember what the name of the set was. This guaranteed that I could not use some simple bootstrap styling to make my dropdown menu. Instead, I had to construct one from scratch.

First I needed the data from the Scryfall API. The line highlighted below returns a list of JSON objects that contains all the MTG sets. All the data I needed for this component comes from this call, including the URLs for the icon SVGs.

SetFilter.vue
   // ...
   created() {
      this.fetchData('https://api.scryfall.com/sets')
      // ...
   }
   // ...

Next, I needed to decide exactly how many of the sets I was going to display. Ironically, even though the set icons are used to help identify what sets certain cards belonged to, the same icon is sometimes used for multiple sets or sub-sets. As far as Scryfall is concerned, the promotional cards or tokens from any given set actually belong to their own sub-set. I didn't exactly agree with this categorization, so I went through the effort to undo this splitting.

SetFilter.vue
   // Look through all of the available set codes.
   for (let d of data) {
      // If the set has a parent code, don't include it in the set list.
      if ('parent_set_code' in d) {
         // Instead, add it to a list related to that original set.
         if (d.parent_set_code in subCodes) {
            subCodes[d.parent_set_code].push(d.code);
         } else {
            subCodes[d.parent_set_code] = [d.code];
         }
         // Save some lookup data for later.
         parentLookup[d.code] = d.parent_set_code;
      // Otherwise, the set should be a "base" set and should be included.
      } else {
         sets[d.code] = {
            // ...
         };
      }
   }
   // Then it's possible for the sub codes to be chained together.
   let tempCodes = subCodes;
   do {
      for (let s in tempCodes) {
         // If the key is not a base set, then append it to it's own base.
         if (!sets.hasOwnProperty(s)) {
            subCodes[parentLookup[s]] = subCodes[parentLookup[s]].concat(subCodes[s]);
            delete subCodes[s];
         }
      }
      tempCodes = subCodes;
   // Repeat this process until the number of lists stops changing.
   } while (Object.keys(tempCodes).length != Object.keys(subCodes).length);

It's not the most elegant solution, since it requires looping an indefinite amount of times, but this block only gets run a single time for when the user loads the page. This additional work actually turns out to be useful in later queries to Scryfall as well. Since Scryfall has all these cards divided, I save these codes together for later to ensure all cards from a related set appear together.

The images are then set inside of a span element, in front of any related text as their own Set components. The selected option is actually a button element. When clicked, it produces an unordered list element of Set components that is hidden once a selection is made. This was possible with Bootstrap's dropdown-toggle, dropdown-menu, and dropdown-item classes. Together, these three make for customizable menus that can look similar to select option elements.

Data Tables

Once the data is queried for the set (and all of it's sub-sets), they are displayed across three different tables.

The first table pulls printings with the lowest market value. This helps determine if the card is valued for its mechanics. Cards like basic lands, although valuable depending on the art, are so common that it's possible to purchase them for pennies on the dollar. Basic lands will never show up in this table. Other cards that are similarly useful but common also won't appear here. As I go through my own cards, ones I find that appear in this table (even if it's a different printing) are separated out as first picks to add to new decks.

The second table is filled with specific prints from the set that are independently valuable. These are cards that are purchased for their rarity or their specific art. The chances of these cards being valued for their playability is lower. In my collection, these are the first to sell or exchange for cards still needed.

The last table shows cards whose foil value is higher than the specific price queried for but the non-foil versions are valued below that threshold. These cards are also good choices for sale or trade. Some cards have foil prices that are significantly higher than their non-foil counterparts. Since I'm more concerned with playability, there is less personal value in these prints.

Final Remarks

This was a fairly straight-forward project using Vue 3 to build a static web-tool. Vue 3 made it easy to construct components in an object-oriented style and will likely be the basis of future projects.

  • Vue 3
  • Bootstrap 5
  • Sass
  • GitHub Pages