03 Prove
JSON APIs
Objectives
Understand what an API is and how they're used.
Learn to parse a JSON response from an API.
Learn to store and access data in a Map.
APIs
Companies with data-driven websites will often create APIs (Application Programming Interfaces), to allow people to programmatically pull data from their site.
Facebook, Twitter, Google Translate, and Ebay, are just a few examples of sites that provide public APIs.
Developers use APIs for a variety of reasons. Often, they want to pull specific types of data for data-mining. Other times, they might want to create their own applications that use the services of those companies, such as an iOS app that allows you to sell things on Ebay.
While every API is different, the general sequence of steps is usually the same:
-
Sign up for a developer account (sometimes called an API Key) with the organization whose API you want to access and obtain authentication credentials.
-
Send an HTTP request to authenticate with the API using the authentication credentials you were given and receive an authentication token.
-
Use that authentication token to make API requests via HTTP to specific URLs (called "end points") which allow you to retrieve the data that you're interested in.
-
The data is returned in a structured format. The most common data format for APIs is JSON.
Instructor Note:
For the API we will use for this assignment, rather than receiving a token, you simply pass the apikey to every endpoint request.
Assignment
You will write a program that uses the Open Weather Map API to retrieve weather information and forecasts.
Warning
This assignment is more difficult than any of your past assignments. I have purposefully left out many of the implementation details, which will force you to do quite a bit of research on your own.
Make sure you exercise diligence prior to asking for help.
Part I: Obtain an Open Weather Map API Account
As is the case for most popular APIs, Open Weather Map requires developers to first sign up for a developer account and acquire a set of API credentials before using their API.
-
Go to https://openweathermap.org/ and sign up for a free account.
-
After signing up, you will receive your API Key in an email (and it can also be seen on the web site). It looks something like:
APPID=b98ff7327823823c8879261aabc9
.This APPID is your "username" and "password" to programmatically make requests from the API. You should treat it like you would any other password, and not share it with others or post it to GitHub, etc.
-
Test your application token and the API by putting the following URL in the browser:
https://api.openweathermap.org/data/2.5/weather?q=Rexburg&apiKey=b98ff7327823823c8879261aabc9
(of course, you'll first need to replace the API key in this URL with your own.) This should bring back JSON data corresponding to the current weather in Rexburg.
Security Warning
Note that some of these items are labeled Secret for a reason. You should not share these values with anyone. You should remove them from your code before submitting it.
With these token values, anyone can access this API as if they were you.
This same caution is generally true for all APIs that use authentication tokens.
Part II: Connect to the API with Java
We'll be using the GSON library to help us interpret the data, just like we did in the team activity. (Please refer to the team activity for more information about using GSON.)
In addition to the GSON library, we will make use of the built-in URLConnection class in Java to help make our web requests.
Please read over at least the first part of StackOverflow: How to use java.net.URLConnection to fire and handle HTTP requests. Please note that we will be using HTTP Get requests with query parameters.
Following the example on the above StackOverflow article (and potentially other Web references), complete the following:
-
Create a new IntelliJ project.
-
Add a reference to the GSON library as you did for the team activity assignment.
Follow the example above of HTTP Get requests to make a request to the same endpoint you did earlier in the browser, and verify that you can get the JSON response back and display it to the screen using Java.
Part III: Create a Class to Store the Data
There is a lot of information in the responses we will get back, but for this assignment we only care about some of it.
As we did in the teach assignment, we'll be creating a class to hold just the data we're interested in.
-
First, create a WeatherConditions class that can hold some of the information you are retrieving back. To start with, it should contain:
id
name
main
Notice that
id
is aninteger
,name
is aString
. On the other hand,main
might look something like this:"main": { "temp": 286.99, "pressure": 1013, "humidity": 53, "temp_min": 286.45, "temp_max": 287.55 }
Where it maps a key of type String to a value of type float (e.g., "temp" is a key that maps to a value of 286.99). Thus, you might choose a data structure, like
Map
which has generic types,String
for the key andFloat
for the value, such asMap<String, Float>
. Verify that you can load the current conditions and use GSON to deserialize them into a
WeatherConditions
object.-
Now, when the GSON library deserializes a JSON String into a class instance, it expects the key names in the JSON to exactly match the variable names of the class.
Sometimes this isn't ideal, such as a name like "main", so it provides a way for you to specify which JSON key should connect to a given variable in a class.
In our case, let's change the name of our
main
member variable tomeasurements
and then tell GSON, to match the two up. To do so, we need to add an "annotation" to our variable to tell GSON that "main" should go withmeasurements
.Modify the declaration of
measurements
in your class so it contains the following line, right before the member variable is declared:@SerializedName("main")
-
Add to your program the ability to prompt the user for a city name and use it, rather than always using "Rexburg" in your API calls.
-
Verify that you can use your code to request data for different cities, and that you can use your measurements map to display the current temperature for each one.
As you do so, you'll likely notice that by default, it displays temperature in Kelvins, which is likely not your preferred unit of measurement.
Look into the API information on their website and figure out how to change your call so that you can have them send you the temperature in your preferred units.
Part IV: Working with Forecasts
In the previous part, we obtained current conditions for a given city. In this part, we will request forecasts for a city rather than simply its current conditions.
The forecast API for 5 day weather forecasts (getting forecasts for 3 hour increments during these 5 days) is outlined here: https://openweathermap.org/forecast5 .
Using this API endpoint, follow these steps to add additional functionality to your program:
-
Create a
WeatherForecast
class that matches up with the results of this endpoint. Notice that this contains a list of individual forecast items or events for every 3 hour period. -
Create a
WeatherForecastItem
class that contains the information of the 3 hour period.Make sure that when you deserialize your JSON, it creates a
WeatherForecast
object that contains a list ofWeatherForecastItem
s. -
Each
WeatherForecastItem
should contain "main" measurements information, "weather" a list of possible weather conditions, wind, and the time (dt or dt_txt) for the forecast.Choose appropriate data types to deserialize each of these items to. Some of these could be new classes that you create, others could make use of collections (e.g., Maps, Lists, etc.).
Have the program give the user a forecast for their specified city. It should display a list of the following for each 3 hour period:
Time
Temperature
A description of the weather conditions (e.g., "clear sky")
Wind speed
Once you've made it this far, move on the stretch challenge.
🌟Stretch Challenge🌟
Rather than work with a single city, use a list of at least 5. (You can either allow the user to type them in, or you can have them hard-coded into your Java code.)
For each city in the set, obtain the weather forecast.
Prepare a data structure that contains the city as well as the maximum temperature and the maximum wind speed expected at any point in its upcoming 5-day forecast.
Sort the cities by maximum temperature and display the results. Then, perform a separate sort, this time by maximum wind, speed and display the results.
There are several ways to accomplish this. The most elegant methods make use of Collections.sort()
and either a custom Comparator
class, or a lambda function.