Downloading Weather Data Using an API

While it’s nice to make programs with objects, loops, user input, etc. the fact of the matter is that most useful apps these days need to do something over a network, whether it’s downloading a file, uploading a file, or making API calls to send and receive data. We are increasingly connected, and this trend is only going to continue. For this section, I made a program that downloads weather data from an API, or Application Programming Interface. In this case, I used the OpenWeatherMap API. If you want to follow along and do this yourself, you will first need to make an account so you can get something called an API key, which is a way to use an API.

OpenWeatherMap’s servers have weather data, which can be accessed by the API. Unlike a library, the remote API code never runs in your program. You are querying a remote server. You can send API calls, and you get responses. But how it works behind the scenes is unknown to you, and it requires an internet connection in order to work properly. Companies like making APIs because it allows users/customers to interact with them without getting to see their private intellectual property, like the code they make that enables them to provide you with data. Some people dislike how more things require internet connections, but the fact of the matter is that software isn’t just offline and only running on a single computer anymore. Whether it’s a computer program or a mobile app, most software has some sort of network connectivity these days.

It can get a little confusing because Oracle calls their default Java library an API. Any time you import stuff into your program that isn’t an externally-downloaded dependency, it’s using the Java API. But that is a local API, which is more like a library (a collection of prewritten code that you can incorporate into your program after you download and import it). In this particular case, when I mention the weather API, it’s a remote API that gives you JSON data.

To sign up for OpenWeatherMap so you can access their weather API data, go here and make an account:

https://home.openweathermap.org/users/sign_up

You will then get an email which contains your API key, among other things. Keep this private. Please note that it can take a couple hours for it to become active.

They have many different API features, but the one I’ll focus on here is the “Current weather data” API.

You can query it like so:

https://api.openweathermap.org/data/2.5/weather?q=CityName

However, if you visit that in a browser, you will get a 401 error because of the lack of an API key. 401 means unauthorized.

So you will have to send your API key as well, like so (using an example API key provided by OpenWeatherMap themselves):

https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22

The response is JSON data for the current weather in London.

Here’s what it looks like:

{“coord”:{“lon”:-0.13,”lat”:51.51},”weather”:[{“id”:300,”main”:”Drizzle”,”description”:”light intensity drizzle”,”icon”:”09d”}],”base”:”stations”,”main”:{“temp”:280.32,”pressure”:1012,”humidity”:81,”temp_min”:279.15,”temp_max”:281.15},”visibility”:10000,”wind”:{“speed”:4.1,”deg”:80},”clouds”:{“all”:90},”dt”:1485789600,”sys”:{“type”:1,”id”:5091,”message”:0.0103,”country”:”GB”,”sunrise”:1485762037,”sunset”:1485794875},”id”:2643743,”name”:”London”,”cod”:200}

Line breaks have been removed in order to make it use less data, but I can make it look a little more readable, like so:

{

“coord”:{

“lon”:-0.13,”lat”:51.51

},

“weather”:[{

“id”:300,”main”:

“Drizzle”,”description”:

“light intensity drizzle”,

“icon”:”09d”

}],

“base”:”stations”,

“main”:{

“temp”:280.32,

“pressure”:1012,

“humidity”:81,

“temp_min”:279.15,

“temp_max”:281.15

},

“visibility”:10000,

“wind”:{

“speed”:4.1,

“deg”:80

},

“clouds”:{

“all”:90

},

“dt”:1485789600,

“sys”:{

“type”:1,

“id”:5091,

“message”:0.0103,

“country”:”GB”,

“sunrise”:1485762037,

“sunset”:1485794875

},

“id”:2643743,

“name”:”London”,

“cod”:200

}

The data from OpenWeatherMap uses a license called Attribution-ShareAlike 4.0 International (CC BY-SA 4.0):

https://creativecommons.org/licenses/by-sa/4.0/

But as you can see in the above JSON, querying the API with a valid API key gives you JSON-formatted data. You can then do something like parse it as JSON or even save it to a .json file. There are also optional parameters you can add, such as &units=imperial or &units=metric. I think the default is Kelvin, which is useful for scientific purposes, but not for casually checking the current weather.

In this case, I am using JetBrains IntelliJ. Make a new project and then make a basic Main class with a main method. Configure the build to use the Main class. Test it with a hello world or something.

There is an external dependency required for this project (for parsing JSON), so you need to download it from here: https://repo1.maven.org/maven2/org/json/json/20180813/json-20180813.jar

From there, within IntelliJ, go to File -> Project Structure, then click Libraries. Then click +, then Java. Then, navigate to where you saved the JSON .jar file. Then click OK. Then hit apply and then hit OK.

We’re going to download the JSON data from the API, save it as a file, and then parse it using the aforementioned org.json dependency. Another thing you might want to do is save the API key in a separate file called key.txt and then add it to a .gitignore (if you’re using git with it) so that you don’t make your API key public. Don’t share your API keys with anyone.

But without further ado, here is the code for fetching weather data from a remote API in Java (the exact file path will be different in your case):

//weather api demo

import java.io.*;

import java.net.MalformedURLException;

import java.net.URL;

import org.json.*;

import java.nio.channels.Channels;

import java.nio.channels.ReadableByteChannel;

import java.util.Scanner;

public class Main {

public static void main(String[] args) {

//setting up the url for making the api call

String firstStringPart = “https://api.openweathermap.org/data/2.5/weather?q=”;

String location = “Chicago”;

String secondPart = “&appid=”;

String units = “&units=imperial”; //replace with metric if you want

String apiKey = “”;

boolean failed = false;

boolean fileDownloadCompleted = false;

//getting api key from key.txt file

//be sure to use .gitignore for the key

//so it’s not made public

try {

Scanner keyIn = new Scanner(new File(“C:\\Users\\Alan\\IdeaProjects\\weatherApi\\src\\key.txt”));

apiKey = keyIn.nextLine();

} catch (FileNotFoundException ex) {

System.out.print(“oops”);

ex.getMessage();

failed = true;

}

//proceeds if no file IO issues

if (!failed) {

String fullUrl = firstStringPart + location + secondPart + apiKey + units;

//System.out.println(fullUrl);

try {

URL apiCall = new URL(fullUrl);

try {

//note: this will always write over an existing weather.json file

//which is what I want

ReadableByteChannel myChannel = Channels.newChannel(apiCall.openStream());

FileOutputStream fout = new FileOutputStream(“weather.json”);

long max = Long.MAX_VALUE;

fout.getChannel().transferFrom(myChannel, 0, max);

//the file is now downloaded and saved as weather.json

fout.close();

myChannel.close();

fileDownloadCompleted = true;

} catch (IOException e) {

System.out.println(e.getMessage());

}

} catch (MalformedURLException m) {

System.out.println(m.getMessage());

}

}

//finished with file download stuff

//now need to parse the JSON to show weather

if (fileDownloadCompleted) {

//System.out.println(“File downloaded sucessfully. Proceeding…”);

try {

//converting json file to a string

Scanner scan = new Scanner(new File(“weather.json”));

String jsonString = “”;

while (scan.hasNextLine()) {

jsonString += scan.next();

}

//turning the string from the file to a JSON object

JSONObject fileToObj = new JSONObject(jsonString);

//System.out.println(fileToObj.toString());

//getting the temperature

JSONObject mainPart = fileToObj.getJSONObject(“main”);

String tempString = mainPart.get(“temp”).toString();

System.out.print(“In ” + location + “, it is currently “);

System.out.print(tempString + ” degrees. The weather is “);

//getting the description

//annoying due to JSON nesting

JSONArray weatherArray = fileToObj.getJSONArray(“weather”);

JSONObject arrayToObj = weatherArray.getJSONObject(0);

String descString = arrayToObj.get(“main”).toString().toLowerCase();

System.out.println(descString + “.”);

} catch (FileNotFoundException fnf) {

fnf.printStackTrace();

}

}

}

}

/* got some help from this source:

https://examples.javacodegeeks.com/core-java/nio/java-nio-download-file-url-example/

*/

Here is the output of the above program:

In Chicago, it is currently 60.04 degrees. The weather is clear.

This section is quite long as it is, so I’m not going to do a line-by-line explanation of how it works. But the point I’m making by showing this weather data downloading program is that there are lots of really cool and powerful things you can do in coding that involve remote servers, such as for an API.

It’s okay if you don’t understand all of the code in this particular section, but I just want to get you more interested in APIs, data, and networking in general. Offline-only apps aren’t as useful as networked ones.

Something else to consider with APIs is validating the data you get from them. In a perfect world, nobody would get hacked. But in reality, things happen. As such, it can be good to validate any data you get from an API to make sure it’s non-malicious. You might trust an API’s developers, but what if they get hacked? If a provider of an API gets hacked, it’s possible that the hackers could make the API give malicious responses to API calls. It’s not likely, but still possible. I didn’t do any special validation in the previous weather API code example, but it’s something to consider. And aside from malicious things, sometimes it’s possible for there to just be mishaps where something went wrong and you get back a weird response rather than the usual data you’re expecting. The takeaway here is that you can never fully trust data from an external source and you need to validate it.

← Previous | Next →

Java Topic List

Main Topic List

Leave a Reply

Your email address will not be published. Required fields are marked *