Shipping with APIs

The questions below are due on Thursday August 05, 2021; 11:00:00 AM.
 
You are not logged in.

Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.
Overview

For this exercise we will be tasked with assessing an order to determine the number of ice packs needed in the shipping container. Please download this zip file HERE containing a skeleton file that you should work in and a file of tests. To run the test cases, make sure the file where you are writing code is named lab.py and then you can run the test.py file as you would any other Python file. The test file has the same test cases as the code checker so it will be useful in debugging.

In this problem, we will be given orders of the form:

{"ID":"52", "Address":"100 Valley Drive", "City":"Helena", "State":"MT", "Zip Code":"59602", "Item":"tomatoes", "Amount":"17"}

And expected to output an integer number of ice packs required for this shipment. Our company has an extremely sophisticated formula for the number of ice packs:

N = \max(0, (T - 70)*D/1000)

where N is the number of ice packs. T is the maximum temperature of the shipping location (Cambridge MA, 02142) on the shipping day and the temperature of the delivery location on delivery day. D is the distance between shipping and delivery locations. Note, since the number of ice packs should always be an integer, we should round any decimal amounts up so we still have enough cooling capacity.

We also provide you with some useful tools:

  1. A csv file ZIP_codes.csv for determining latitude/longitude of various zipcodes
  2. An API endpoint that we can call with a latitude and longitude to get a url for finding weather data
  3. An API endpoint for determining distances between two zip codes

Before you start coding though, please go through the next section introducing API usage.

Intro to APIs

For this exercise we're going to be learning about APIs. An API, or Application Program Interface, is: a way to communicate with other applications - usually sending and receiving data.

The most common form of API is a web API that is performed by sending an HTTP request, or essentially visiting a URL of website. But instead of returning a pretty web page it'll return data packaged in a string that looks very similar to a python dictionary. In fact we can use some tools to convert it directly into a python dictionary. We'll be using web apis for this exercise.

Weather API

For example if in another tab you visit this URL, you'll see the weekly forecast for Alliance, Nebraska - home of the famous Carhenge. This is an example of the weather api you can read about at api.weather.gov.

There's a lot of information here, tucked inside nested dictionary format, but what we'll mostly be concerned with are the "periods" which show daily temperatures, such as:

"periods": [
            {
                "number": 7,
                "name": "Monday",
                "startTime": "2021-07-12T12:00:00-06:00",
                "endTime": "2021-07-12T18:00:00-06:00",
                "isDaytime": true,
                "temperature": 90,
                "temperatureUnit": "F",
             },
            ]

From which we'll be able to know that Monday, July 12 has a high of 90 degrees. That's all very helpful, but how do we determine what the URL we need is? Fortunately, the weather api has a another endpoint that takes in a latitude and longitude and will help us figure out the forecast URL. For example, try visiting:

https://api.weather.gov/points/42.1423,-102.8580

You'll see that down below the key "properties" maps to a dictionary, and in that dictionary there's a key for "forecast". The value of forecast is the URL for the forecast API.

To test your understanding, try finding the high temperature for Cambridge, (42.393246,-71.133833) for tomorrow and enter the result rounded to an integer below. Hint, you'll need to edit the above URL to use the coordinates for Cambridge. Then you can visit that page and find the URL for the forecast API for Cambridge.

For this API, we format the url as such, filling in the respective areas for latitude and longitude:

https://api.weather.gov/points/<latitude>,<longitude>

Enter your answer as an integer:

Calling APIs in Python

Now you're able to visit an API manually, but let's see how to do the same process in code. We'll be using the requests library in order to retreive the data you saw on your browser, and then convert it into a python dictionary. For example, the following code will retreive the same data as visiting the url. We then convert the response to a python dictionary using the .json() method.

import requests

url = "https://api.weather.gov/points/42.1423,-102.8580"
response = requests.get(url)
data = response.json()
print(data)

Check yourself by writing python code to visit that url, and then extract the forecast url from the returned dictionary. Then use the extracted url to make another api request and get the forecast data from the response. For this exercise, we will only use the temperature from the period with number equal to 1, so let's do a warmup to extract and print that temperature. Check below to see an example after trying yourself.

import requests

url = "https://api.weather.gov/points/42.1423,-102.8580"
response = requests.get(url)
data = response.json()
forecast_url = data['properties']['forecast']

response = requests.get(forecast_url)
data = response.json()
for period in data['properties']["periods"]:
    if period['number'] == 1:
        print( period['temperature'])

API Keys

Some APIs require you to have an account in order to use the service. We'll only be using free APIs right now, but one of them (the zipcode distance API) requires making a free account. You should do so here by clicking on the green Free Key button. You'll receive an email and be able to access an API key whcih is a string of characters. You can use "Shipping API" as the application name and we recommend signing up with an email that you don't care about much to avoid spam. Once you've signed up, you will be able to get an API key here. We'll include the API key as part of the url for the API request.

For this specific API, we format the url as such:

https://www.zipcodeapi.com/rest/<api-key>/distance.<format>/<zip1>/<zip2>/<unit>

For example, when we call the API, we use the staff key of 65wLFxIkjMfl9c3VfbqPdRQST9ZmnYEz9DDZ9xy1NySkOsJFsW73V8isUYDdaBnb. We'll use json for the format so we can easily convert the response to a Python dictionary. An example url is as follows:

https://www.zipcodeapi.com/rest/65wLFxIkjMfl9c3VfbqPdRQST9ZmnYEz9DDZ9xy1NySkOsJFsW73V8isUYDdaBnb/distance.json/02115/59602/mile

To check yourself, use either python or a web browser to find the distance between Cambridge (02142) and Brooklyn (11222).

Enter your answer as a float:

Implementation

Now that we've gone over how to use these API tools, let's revisit what we need to accomplish in this assignment and the high level functionality of get_ice_packs(order).

As an example if we input this order

{"ID":"52", "Address":"100 Valley Drive", "City":"Helena", "State":"MT", "Zip Code":"59602", "Item":"tomatoes", "Amount":"17"}

Then we'll use the csv file ZIP_codes.csv to determine the latitude and longitude for the start and destination zipcodes. Next we use those to call the weather API, and we'll say we got 80 degrees for zipcode 59602 and 75 degrees for zipcode 02142 for their respective period 1 entries. According to the zipcode api, the distance is 2009.656. Then according to the formula, we would need (80-70)*2009.656/1000 = 20.09, or 21 whole ice packs. Our function should then return the integer 21.

Submit your finished code below and note that the tests run are the same as those in the test.py file you downloaded.

 No file selected

Next Exercise: Dual Generation

Back to exercises