Connecting an API-Driven Web App with Javascript

Final product image
What You'll Be Creating

We have our little app looking just the way we want, but it doesn’t actually do anything yet. So, let’s work on adding some JavaScript to make the app interactive.

This part of the series will require some concentration from you, but even if you’re not a seasoned JavaScript developer, I promise you will walk away having learned some valuable skills.

Initial Setup

First, we’ll create our javascript file assets/js/main.js and inside of that we will create an object called Gimmie (named after our app). This is where we will store the variables and functions we need so that they’re not on the window object. We’ll put it right next to jQuery’s “document ready” call that we’ll also be using.

Notice that we added a few variables in our Gimmie object: $content, $form. These are jQuery objects, so we name them with a $ in front to remind us of that. Since they are specific DOM nodes that we will reference more than once we will store them in variables for faster, future use.

Form Submission

The first thing we need to handle is when the user enters something into our form and submits it. So, inside our “document ready” we will attach a listener event to our form. We could do $('form').on() but because we’ve already stored the form element in a variable, we’ll just reference that instead, by doing Gimmie.$form.on(). Then we will prevent the default form action (so the page doesn’t refresh):

Loading

Now, we want to show a “loading” state when a user submits the form. That way they know something is happening. If you remember, we designed this in Sketch:

Screenshot of the loading state in Sketch

To accomplish this, we will create a function inside our Gimmie object called toggleLoading and we can execute it when the user submits a form by calling Gimmie.toggleLoading() inside our form submission listener. We named it toggleLoading because we will toggle the current loading state in the UI, i.e. we execute it once on submit, then we’ll run a bunch of code, and when we’re done we will run it again to take away the loading state.

Notice that we are toggling a class on the .content element called content--loading. We need to create some CSS styles around that. So, in our CSS file, let’s add:

Here we use pseudo elements to create a loading state on our content area. Our before element is used to create a slightly opaque white overlay on the content area. Then we use the after element to display an animated loading gif inside our box. When this class is added to our content section, it will appear as if something is loading.

At this point, if you enter anything into the input field and submit the form, a loading state will display and you’ll just be stuck at that.

Screenshot of form loading

Form Validation

Before we submit a request to the iTunes API, let’s make sure that the data being entered by the user is correct.

So what exactly constitutes correct data? Well, if we look at the iTunes API documentation there are a few different ways of getting content. One way is to do a search based on key terms. But what we’re going to do instead is called a “lookup”. From the docs:

You can also create a lookup request to search for content in the stores based on iTunes ID

It then gives a few examples, such as looking up the Yelp Software application by its iTunes ID: https://itunes.apple.com/lookup?id=284910350. Notice that the application’s ID number is what is shared between these URLs. That’s what we will need from the user.

Example of iTunes API and store urls

From a UX perspective, asking for an identifier to an app in the app store might prove to be a little difficult (especially for novices). So instead of instructing people how to get an app’s ID, we’ll ask for the app’s store link. Everyone knows how to copy and paste links! App links are readily available to anyone by simply copying them from the individual app’s page in the app store (in iTunes, on the web, or in the Mac App store).

App store links

So, once the user enters a link, we need to validate it:

  1. Make sure it is a valid url that begins with http://itunes
  2. Make sure it contains an ID

To do this, we’ll create a validate function inside of our Gimmie variable and execute it on our form submit event listener.

Note what we’re doing in the code above:

  • We add a few variables and one function to Gimmie
    • userInput is a string and is set as the input from the user
    • userInputIsValid is a boolean which will be true or false depending on whether the input from the user is valid (we’ll write those tests in a moment)
    • appId is a string of digits which will be extracted from userInput if it’s valid
    • validate is a function where we will validate the user’s input when called
  • On form submit, we:
    • Set Gimmie.userInput to the value of the form’s input field
    • Execute the validation function in Gimmie.validate()
    • Run an if/else statement. If the user input is valid (something our Gimmie.validate will determine) then we will proceed and make an iTunes API request. If it’s not valid, we will display an error informing the user that the data they entered is not correct.

Now let’s write the code that validates whether or not the user input is correct. Note that in our HTML we set our input type to url <input type="url">. This means some browsers will natively perform some type of validation on that input, however it will not be consistent or uniform across browsers. In some browsers, it won’t even work. So if the user types “blah”, the browser will accept it and the form will submit. In other browsers, they will at least have to type something that begins with “http://” before the browser will let them submit the form. But what we want is a URL that begins with “http://itunes”, so we will handle that in JavaScript.

Here we are using regular expressions to test whether or not the input meets our conditions. Let’s walk through this in a little more detail:

These are the two regular expression literals we define (read more about regular expressions). Here’s a brief summary of what those regular expressions are doing:

http://itunes regex
  • regUrl is the regex literal for determining whether or not the user input is a URL that begins with “http://itunes”
    • /^ says “start the regex and begin looking at the beginning of the string”
    • (http|https): says “look for either ‘http’ or ‘https’ followed by a semicolon ‘:’”
    • \/\/ says “look for ‘//’” (because a forward slash is a special character in regular expressions, like the way we use it at the beginning of the regex, we have to use the backslash before the forward slash to tell the regex not to interpret the forward slash as a special character, but rather as just a forward slash)
    • itunes/i says “look for ‘itunes’ then end the regex” while the i at the end indicates the matching should be done case insensitive (since somebody might paste ‘HTTP://ITUNES’ that is still valid)
/id"digit" regex
  • regId is the regex literal for determining whether or not the user input has an ID of digits matching the iTunes store link URL pattern. All valid iTunes store links will have /id in it, followed by a sequence of numbers.
    • /\/id says “start the regex and look anywhere in the string for ‘/id’” (see previous example for forward slash escaping description)
    • (\d+) says “look for a sequence of digits (0 through 9) 1 or more times and capture them”. The parenthesis indicate that we want to remember whatever match is defined inside, i.e. in our case we remember the sequence of digits which represents the app’s ID. The /d is a special character in regex indicating we want digits [0-9] and the + says match those [0-9] 1 or more times.
    • /i says “end the regex” and the i indicates case-insensitive matching (since a URL with /ID938491 is still valid)

The next bit of our code looks like this:

The .test() method on a regex literal looks for a match from a specified string and returns true or false, depending on if the specified match is found. So, in our case, we test the user’s input against both regUrl and regID to ensure that the input both begins with “http://itunes” and has “/id” followed by a number of digits.

If both tests return true, we set the userInputIsValid flag to true and then we extract the ID from the URL and set it as appId. To do this, we run the .exec() method on the input. This will return an array of two items: one matching the entire regex, and one matching just the string of numbers after /id (this is because we used the parenthesis in the regex (/d+) to say “remember what gets capture here”). So, as an example, the .exec() method would return something like ["/id12345", "12345"] and we want just the second item in the array, so we set appId to that.

If both tests return false, we set userInputIsValid to false and the appId to an empty string.

Now everything we need to determine whether the user’s input is valid is in place. So we can continue with the rest of our script.

Throwing Errors

Right now we are at a point now in our script where we can determine whether or not the user’s input is what we need. So we left off with this:

For now, we are going to handle the “throwing an error” part. Because there are going to be other spots in the execution of our script where errors can occur, we are going to make a generic error function that will display an error to the user, depending on what went wrong. If you remember, we designed what this would look like in Sketch:

Screenshot of the error state in Sketch

Notice how our error state has essentially two items: a “header” that is bolded text, and a “body” which is regular set text. So we will create a generic error function which accepts these. The “header” will generally state the error and the “body” will describe how fix the error. So, in this particular case, if the input from the user is invalid we need to inform them what a proper input type is. So, let’s create a generic function that can show errors based on the text we pass it:

Here, we call the function Gimmie.throwError() and pass it two parameters: the “header” text and the “body” text. Because we are just displaying HTML, we can pass HTML elements inside the parameters if we wish. In this case, in the “body” we pass in an example iTunes store link and we highlight the id/ part with the emphasis tag (<em>) to help indicate to the user, “hey, we need an iTunes store link, and make sure it has an ID in it”.

We can set our CSS to highlight whatever is wrapped in <em> tags, as well as giving our error state a color:

Now, we will create the throwError function in the Gimmie object:

Notice that we are grabbing this.$content. This is the same as doing $('.content') but we saved that selection as a variable in the Gimmie object, since we will use it more than once. So we reference it by doing this.$content. Now we set the HTML contents of the $content element to the text we passed in, with the “header” text being bolded. Then we add a class of content--error to our content element that way we can style the errors how we wish. Lastly, we run the toggleLoading() function of Gimmie to remove the loading class and stop displaying the loading gif.

At this point, if you type in an incorrect URL like http://google.com, or if you type in a proper iTunes URl that doesn’t have an ID like https://itunes.apple.com/us/app/twitter/ you should see an error message displayed:

Screenshot of incorrect URL

To enhance our form a bit, let’s add a nice little “pop” animation that runs when an error occurs (in supported browsers). To do this, we’ll add/remove a CSS class that contains an animation. So, in our CSS file, let’s do:

That will make the content area scale up and down in size, making it “pop” when an error occurs. Now we just have to add/remove that class with JavaScript. So back in our throwError function:

Here we remove the class first, then we trigger a “reflow” to ensure that the animation starts again when we add the class in the next step (along with the regular content--error class). Now we have a nice pop animation on our error state as well:

Animated gif of css animation

Making an API Request

We are getting close to finishing now. We’ve checked to make sure the input from the user is correct and we’ve provided a way to display errors, so now we just need to make our API request.

We’ll do this inside our if() statement that validates the user’s input.

As you can see from the code above, we’ve setup an AJAX request to the iTunes API. As you may remember from earlier, the iTunes API has a “lookup” URL we can hit to get data back. It follows this format: https://itunes.apple.com/lookup?id= followed by the ID of the thing you want to find. The API gives an example of a software application lookup using the Yelp app: https://itunes.apple.com/lookup?id=284910350. If you go to that URL in your browser, you’ll see a mess of JSON:

Screenshot of iTunes API response

If you run that through a linter, like JSON lint, the results will be formatted and will begin to make a lot more sense:

Screenshot of iTunes API response formatted

If you look at the API documentation, you’ll notice that the API provides results for all kinds of content in the iTunes store, everything from music to movies to apps. That is advantageous to us because it means we can grab icon artwork not just for iOS apps, but Mac apps as well! Mac apps use the same type of URL structure as iOS apps. For example, Final Cut Pro has a link of https://itunes.apple.com/us/app/final-cut-pro/id424389933?mt=12. Note that the URL begins with https://itunes and has /id424389933, which is just what we need!

Using our error function from earlier, let’s throw an error for if/when our API request fails:

As we abstracted our method for displaying errors into a single function, displaying another error is easy!

The Response

Now let’s worry about what happens when the request completes successfully:

Note here that we are getting the response and logging the first result to the console. If you look at an example API request you’ll see that at the top most level of the JSON object, you get resultCount which tells you how many results there are (in a lookup there should only be one) and then results which is an array (with a single object in this case) which represents the result.

Example API results

So, we set the response to the first item in results and then log it to the console. If you open our little app in the browser and enter a URL (for example, the Yelp URL https://itunes.apple.com/lookup?id=284910350) you’ll see the UI be stuck in the loading state, but if you look at the development tools and go to the console, you’ll see our API response logged. We can now access any of those properties in JavaScript!

API results logged in browser

As you can see, the API returns a bunch of information about the app: its name, developer, description, genre, price, and much more! We really only need a few of those things, like the app’s icon. So, we will check to just make sure our request contains the pieces of information we need.

Here we check to make sure response exists and we check to make sure response.artworkUrl512 is part of that response. artworkUrl512 is the key that the API provides for a link to the full size app icon. If those things are present, we are going to display the app icon on the page. For that, we have another function called render which we will write in a moment. If for some reason the stuff we need is missing, we throw another error with our nice function we already made.

Rendering the API Results

Now that we have the API returning the data we want, let’s render the results on the page. Once we know we have everything we need from the API, we call Gimmie.render(response) and pass the API response to it, which is just an object of key/value pairs. So, back in our Gimmie object, let’s create the render function:

Here’s what we are doing in this code:

  • To create an image from scratch, we create a variable named icon and use the Image() constructor which basically creates an HTMLImageElement. Think of it like creating an <img> tag in memory using JavaScript.
  • We then set the src attribute of our image by using the icon.src method available to use because we used the Image() constructor. We set the image’s source to the artworkUrl512 of our response. This will make the browser begin fetching the image at that specified URL.
  • We use icon.onload to tell the browser “when you’re done fetching the image, do this…”. This is a way of having the browser fetch an image resource and then not actually put it into the DOM until it’s been downloaded.
  • Inside of icon.onload we set the HTML of $contents to the image we just retrieved. Then we can append more information to that content area if we want. In this example, I grab the trackName from our API response to show the app’s name along with its icon.
  • Lastly execute our toggleLoading function because we’re done loading everything!

Try running this in your browser now and you should see a nice icon show up! For example, try the Yelp URL https://itunes.apple.com/us/app/yelp/id284910350?mt=8

Screenshot of API success for Yelp icon

Try it with a Mac app URL, like Final Cut Pro https://itunes.apple.com/us/app/final-cut-pro/id424389933?mt=12

Screenshot of API success for Final Cut Pro icon

Loading the Icon Mask

Notice that the iOS icon is not rounded. As noted earlier, most iOS icons are not designed with rounded corners. Those are applied at the OS level. For iOS icons, we will have to apply the mask we created in Sketch. So, if you go into Sketch and export that mask we created as an image asset, we’ll load that into the browser when we load the icon:

Here’s what we are doing:

  • In our API results, there’s an object called “kind” which refers to the kind of thing being returned by the API, like movie or music or software. Mac apps will have a “kind” of “mac-software”. Because Mac apps don’t need a mask applied to their icon, we check to see if the response kind is not “mac-software”. If it’s not, we know it’s an iOS app and then we can load the mask
  • We use the same Image() constructor as before, set the src of the image to where we saved our mask, and then prepend it to our content area once the onload event fires for the image.

Now we just have to add some styles for positioning the mask over the icon:

That’s it! If you enter the Yelp URL again, this time it will appear with rounded corners!

Screenshot of icon with mask

Complete!

It’s been quite a journey, and I hope you’ve learned a lot from this tutorial! We covered creating wireframes and mocks for our app and its different states. We also covered writing HTML, CSS, and Javascript for a web app that interfaces with a third-party API.

Hopefully you’ve grasped a few basics of interfacing with an API. You’ve learned how to dynamically pull content and assets from an API and render it all into a web page. With that basic knowledge you can now move onto creating more personalized web apps tailored to your interests.

Here’s a list of a few APIs out there:

Tags:

Comments

Related Articles