Photo by Fotis Fotopoulos on Unsplash
API Basics¶
Overview¶
This notebook will cover the terminology and steps needed to retrieve data from an API
Prerequisites
Motivation
API Terminology (and Status Codes)
Imports
Example: Weather API
Summary
Prerequisites¶
Concepts | Importance | Notes |
---|---|---|
Intro to Pandas | Necessary | Familiarity with working with dataframes |
Intro to Matplotlib | Helpful | Plotting on a data |
Motivation¶
There are many ways to gather data. Science and research entities like NASA are constantly producing and collecting data. As a result, attempting to collect and display live data can be difficult since new data is always being added. An API is a method to query a data source for the most current data or retrieve data from a remote source. This notebook will cover the basics regarding API usage to improve ease of access to publicly available data.
API Terminology¶
API: Application Programming Interface which dictacts how code can communicate and access or update remote data through methods
Request: Code sends
requests
to an API to either retrieve or update dataGET: A
GET
request retrieves dataSET: A
SET
request updates data
When working with public APIs, most methods will request data from an API (a GET
request)
Understanding Status Codes¶
There are multiple possible status codes that a request will return. For the purpose of simplicity, the two most important codes are:
200 OK: The server was able to successfully process the request and return the requested data
400 Bad Request: The server was not able to process the request do to an invalid request (usally the result of an invalid URL or unknown parameters)
Imports¶
import requests # access API
import matplotlib.pyplot as plt
Requests¶
The Requests Python package is a library that manages the requests made in Python
A request returns machine-readable data in a JSON. Among the data, requests returns:
request.status_code: status code of the request (200, 400, etc...)
request.text: data requested as a JSON
request.json(): fully JSON returned by the request
Example: Weather API¶
The National Weather Serivce manages an API for weather in the United States. The API is hosted at https://api.weather.gov/
The first step when working with an API should be to check that the API is fuctioning by querying a general request without any additional parameters.
weather_request = requests.get("https://api.weather.gov/")
weather_request.status_code
200
Info
A 200 status code represents that the base API is working as expected and a query request returns no errors.
However, without any additional parameters, all the data that the request returns is just the status code.
# All Data
weather_request.json()
---------------------------------------------------------------------------
JSONDecodeError Traceback (most recent call last)
File ~/micromamba/envs/api-cookbook-dev/lib/python3.13/site-packages/requests/models.py:976, in Response.json(self, **kwargs)
975 try:
--> 976 return complexjson.loads(self.text, **kwargs)
977 except JSONDecodeError as e:
978 # Catch JSON-related errors and raise as requests.JSONDecodeError
979 # This aliases json.JSONDecodeError and simplejson.JSONDecodeError
File ~/micromamba/envs/api-cookbook-dev/lib/python3.13/json/__init__.py:346, in loads(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
343 if (cls is None and object_hook is None and
344 parse_int is None and parse_float is None and
345 parse_constant is None and object_pairs_hook is None and not kw):
--> 346 return _default_decoder.decode(s)
347 if cls is None:
File ~/micromamba/envs/api-cookbook-dev/lib/python3.13/json/decoder.py:345, in JSONDecoder.decode(self, s, _w)
341 """Return the Python representation of ``s`` (a ``str`` instance
342 containing a JSON document).
343
344 """
--> 345 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
346 end = _w(s, end).end()
File ~/micromamba/envs/api-cookbook-dev/lib/python3.13/json/decoder.py:363, in JSONDecoder.raw_decode(self, s, idx)
362 except StopIteration as err:
--> 363 raise JSONDecodeError("Expecting value", s, err.value) from None
364 return obj, end
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
During handling of the above exception, another exception occurred:
JSONDecodeError Traceback (most recent call last)
Cell In[3], line 2
1 # All Data
----> 2 weather_request.json()
File ~/micromamba/envs/api-cookbook-dev/lib/python3.13/site-packages/requests/models.py:980, in Response.json(self, **kwargs)
976 return complexjson.loads(self.text, **kwargs)
977 except JSONDecodeError as e:
978 # Catch JSON-related errors and raise as requests.JSONDecodeError
979 # This aliases json.JSONDecodeError and simplejson.JSONDecodeError
--> 980 raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
The next step is to query with specific paramters. For the weather API the accepts either a grid around a NWS Weather Forecast Office or a specific latitude/longtiude position
The request will be formatted as:
https://api.weather.gov/points/<latitude>,<longitude>
More information about the documentation can be found at NWS Weather API.
For example, the location of the NCAR Mesa Lab is 39.97777
degrees latitude and -105.274966
degrees longitude
ncar_weather = requests.get("https://api.weather.gov/points/39.97777,-105.274966")
# Check request returned a valid response
ncar_weather.status_code
Success
With a valid request and paramters, this request will return data as well!
ncar_weather.json()
With the latitude and longtiude of a position, the API will return information about the closest NWS forecast office that can be further queried to return the weather. A JSON acts like a Python dictionary; to return the values stored, json()
can be queried for a specific key.
# JSON as Dictionary
print(type(ncar_weather.json()))
for key, value in ncar_weather.json().items():
print(f"\nkey: {key}")
print(f"value: {value}")
The closest forecast office from the NCAR Mesa Lab is forecastOffice
ncar_weather.json()["properties"]["forecastOffice"]
The query also return the hourly forecast as a further URL to query as a request under forecastHourly
ncar_forecast_url = ncar_weather.json()["properties"]["forecastHourly"]
ncar_forecast_url
ncar_forecast_hourly = requests.get(ncar_forecast_url)
ncar_forecast_hourly.status_code
Note
There is a lot more data returned from this request! The forecast information can be collected under properties and period. Each period of time has various weather values to chose from:
ncar_forecast_hourly.json()["properties"]["periods"][0].keys()
To plot, let’s collect the startTime
, endTime
and temperature
(° F) values
datetime_start = ncar_forecast_hourly.json()["properties"]["periods"][0]["startTime"]
datetime_end = ncar_forecast_hourly.json()["properties"]["periods"][-1]["endTime"]
print(datetime_start)
print(datetime_end)
# Temperatures every hour
hour_x = []
temperature = []
for period in ncar_forecast_hourly.json()["properties"]["periods"]:
hour_x.append(period["startTime"])
temperature.append(period["temperature"]) # collection of temperatures
print(temperature)
# Plot
fig, ax = plt.subplots(figsize=(22, 10))
# Plot Hourly Temperature
plt.bar(hour_x, temperature, color="dodgerblue")
# Setup Axis Limits and Title/Labels
plt.title(f"Hourly Tempearture at NCAR Mesa Lab for the Next {len(temperature)/24} Days")
plt.xlabel("Datetime")
plt.xticks(rotation=90, fontsize=8)
plt.ylabel("Temperature (\u00B0F)")
plt.show()
Success
We have ploted the forecasted hourly temperatures for next week!
Summary¶
In this notebook, we have...
covered basics about API terminology
gone through a practice example of requesting data from the National Weather Service API
generated a plot of forecasted temperatures
What’s next?¶
Now we can continue investigating other APIs using some example workflows in this cookbook.