Monday-Tuesday: JSON & APIs Copy

JSON

JSON (JavaScript Object Notation) is a standardized format for structuring data. This format is heavily based on the syntax for JavaScript objects. When working with external servers or APIs the data that you would be receiving are most likely to be in that format. JSON is essentially the universal format for transmitting data on the web.

Go through the following resources and you will be in a good shape:

  1. This MDN tutorial is really all what you need.

  2. Go through JSON.parse() and JSON.stringify(). These are the two most used JavaScript methods.

  3. A common cause of errors is the mis-formatted JSON. This webpage lets you paste in JSON code and will search it for formatting errors.

Additional Resources


Introduction

As a web developer you will have to do several tasks. One of the most important and powerful task is to fetch data from a server and creatively display them on the site. The server can contain several things, such as blog posts, user data, high scores etc. Furthermore in other cases the server is an open service that serves data to anyone that wants to use it. The methods that we access and use the data is the same no matter the case.

Introduction to APIs

APIs or Application Programming Interfaces are servers that are created for serving data for external use. Let’s see a short video of what an API is.

There are several ways of requesting data from an API. However all of them basically do the same thing. APIs are accessed through URLs, and the specifics of how to query these URLs changes based on the specific service we are using.

Let’s see how we can fetch data from the OpenWeatherMap API. The OpenWeatherMap API has several types of data that we can request. In order to get the current weather in a specific location, we need to request data from this URL:

api.openweathermap.org/data/2.5/weather?q=London,uk

This url returns some information for the London in UK. If we want to search for a different city, then we need to switch out the city for the location we want. The specifics for using any API are usually documented on the service’s website. Check here for the OpenWeatherMap API documentation.

Now go ahead and paste the weather URL above into your browser. You will probably get the following an error, unless the implementation of that specific API has changed.

{"code":401, "message": "Invalid API key. Please see http://openweathermap.org/faq#error401 for more info."}

This is another key factor about APIs. In most cases, we have to sign up and get an API key to use them. Don’t worry though because the procedure is simple. To obtain the API key we sign up on their website and we use it by pasting it into the URL like this:

http://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=1111111111

(exactly how to include the key changes from service to service)

The reason that services like the OpenWeatherMap use API keys is that they want to track who is requesting the data they serve, and how much data they are requesting. This is due to the fact that they don’t want people to take advantage of their service.

Running large servers costs money. In addition although each weather request is relatively cheap, if the amount if requests gets too high the cost could be significant. If for example you have built a weather app that gets used by people from all over the world, you can have thousands of requests every minute.

Therefore, when we sign up for a service and get an API key, we are letting the service track how much we are actually using. In many cases services are limited as to how much data users can request for free. For example the free plan of the OpenWeatherMap service allows us only to make 60 requests per minute and also limits what types of data we can access. If you are interested you can find more details here.

For the majority of our apps it is fine to use the free service, since our apps will be used by us and the people that view our portfolios.

Once you get a key (try this now if you like!) and waited for its activation (see Do I need to activate my API key?) you can paste the URL into the browser again (including your key of course) and hopefully, you’ll see a proper response:

{
    "coord": {
        "lon": -77.73,
        "lat": 38.77
    },
    "weather": [ {
        "id": 800,
        "main": "Clear",
        "description": "clear sky",
        "icon": "01d"
    } ],
    "base": "stations",
    "main": {
        "temp": 75.74,
        "pressure": 1017,
        "humidity": 57,
        "temp_min": 71.6,
        "temp_max": 78.8
    },
    "visibility": 16093,
    "wind": {
        "speed": 3.87,
        "deg": 291
    },
    "clouds": {
        "all": 1
    },
    "dt": 1504188900,
    "sys": {
        "type": 1,
        "id": 2886,
        "message": 0.0053,
        "country": "US",
        "sunrise": 1504175992,
        "sunset": 1504222878
    },
    "id": 4775660,
    "name": "New Baltimore",
    "cod": 200
}

Access API Data

So the question is. How do we actually get the data from an API into our code?

A few years ago the main way to access API data in your code was using an XMLHttpRequest. Although this function still works in all browsers, it is not nice to use.

The syntax looks something like this:

// Just getting XHR is a mess!
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
  request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
  try {
    request = new ActiveXObject('Msxml2.XMLHTTP');
  }
  catch (e) {
    try {
      request = new ActiveXObject('Microsoft.XMLHTTP');
    }
    catch (e) {}
  }
}

// Open, send.
request.open('GET', 'https://url.com/more/url', true);
request.send(null);

Ouch. That wasn’t simple at all!!!

For this reason developers have begun writing 3rd party libraries to take care of this and make it much easier to use. Some of the more popular libraries are axios and superagent, both of which have their strengths and weaknesses.

However, more recently, web browsers have begun to implement a new native function for making HTTP requests. This function is fetch() and it is the one that we are going to be using and stick for now.

// URL (required), options (optional)
fetch('https://url.com/more/url')
  .then(function(response) { 
    // Successful response :)
  })
  .catch(function(err) {
    // Error :(
  });

Now, scroll back up and look at how you would use XHR to do the same thing. See how nice and clean this code is? Also notice the .then() and .catch() functions. What those are? (PROMISES!)

Now we will see an example using fetch with the giphy API. With this API we will display a random gif on a webpage. The API requires you to sign up and get a free API key. So go ahead and do that here. Giphy has several methods for searching and finding gifs. You can find all about it in their documentation.

In our example we are going to use the ‘translate’ endpoint because it’s the simplest one for our purposes. You can find the appropriate URL in their documentation by scrolling down here. What it tells us is that the correct URL is api.giphy.com/v1/gifs/translate and that it requires 2 parameters, your api_key and a search term.

So if we put it all together and let’s say we are searching for cats then the url that we will get should be something like this:

'https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats'

Now let’s try that URL (with YOUR API key) in a browser. If everything goes well you should get a relatively long string of data and no errors.

Introduction to CORS

Before we start and put all this stuff into our code let’s make a side note. For security reasons, by default, browsers restrict HTTP requests to outside sources. Therefore there is a small amount of setup that we need to do to make fetching work.

Having said that learning about this is outside our scope right now, but if you want to learn a bit about it this you can check out this wikipedia article.

Whether or not you learned all about Cross Origin Resource Sharing (CORS) the fix is simple. By using fetch, you are able to easily supply a JavaScript object for options. To be more specific, it comes right after the URL as a second parameter to the fetch function:

fetch('url.some.com/api', {
  mode: 'cors'
});

So what we need to do is to simply add the {mode: 'cors'} after the URL. For now this will work, but in the future you need to look further into the implications of this restriction.

Time for Practice

For now, we’re going to keep all of this in a single HTML file. So

  1. Create an HTML file
  2. In the body add a single blank image tag
  3. In the body add an empty script tag
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <img src="#" />
  <script>
  </script>
</body>
</html>

Now inside the script tag, we will select the image and assign it to a variable. In that way we can change the URL once we’ve received it from the Giphy API.

<script>
  const myImg = document.querySelector('img');
</script>

Now we will add the fetch with our URL.

<script>
  const myImg = document.querySelector('img');
  fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'})
    .then(function(response) {
      console.log(response.json());
    });
</script>

Now open the HTML file in your browser. You won’t be able to see anything on the page, however you should have something logged in the console.

The trickiest part is how to get to the data you desire from the server’s response. So if we inspect the browser’s console will reveal that what’s being returned is another promise. So in order to get the data we need another .then() function.

<script>
  const myImg = document.querySelector('img');
  fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'})
    .then(function(response) {
      return response.json();
    })
    .then(function(response) {
      console.log(response);
    });
</script>

Now we have a JavaScript object. If you inspect it in the console closely enough you’ll find that the data we need (an image URL) is nested rather deeply inside the object:

response

Therefore, in order to get to the data we need to drill down through the layers of the object until we find what we want!

<script>
  const myImg = document.querySelector('img');
  fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'})
    .then(function(response) {
      return response.json();
    })
    .then(function(response) {
      console.log(response.data.images.original.url);
    });
</script>

Running the file should now log the URL of the image. Finally we need to set the source of the image that’s on the page to the URL we’ve just accessed:

<script>
  const myImg = document.querySelector('img');
  fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'})
    .then(function(response) {
      return response.json();
    })
    .then(function(response) {
      myImg.src = response.data.images.original.url;
    });
</script>

You should now be able to see a new image on the page every time you refresh!

If you’ve gotten lost along the way, check the code below. Besides the glorious styling, this is what your version should look like.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <style>
    body {
      background-color: #e6d8e7;
      display: flex;
      height: 90vh;
      align-items: center;
      justify-content: center;
    }
  </style>
  <img src="#" alt="cat">
  <script>
  const myImg = document.querySelector('img')
  fetch('https://api.giphy.com/v1/gifs/translate?api_key=bb2006d9d3454578be1a99cfad65913d&s=cat', {mode: 'cors'})
    .then(function(response) {
      return response.json()
    })
    .then(function(response) {
      myImg.src = response.data.images.original.url
    })
    .catch(e => {
      console.log(e)
    })
</script>
</body>
</html>

Study

  1. Read the fetch documentation here. You can also watch the last part of this live session which shows XHR and the Fetch API getting data from the Rest Countries JSON API.

  2. Check out this list of free, open APIs and let your imagination go wild.

  3. Expand on our little project here by adding a button that fetches a new image without refreshing the page.

  4. Add a search box so users can search for specific gifs. You should also investigate adding a .catch() to the end of the promise chain in case Giphy doesn’t find any gifs with the searched keyword. Add a default image, or an error message if the search fails.


Leave a Reply