
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
requeststo an API to either retrieve or update dataGET: A
GETrequest retrieves dataSET: A
SETrequest 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 pltRequests¶
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_code200Info
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.
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_code200Success
With a valid request and paramters, this request will return data as well!
ncar_weather.json(){'@context': ['https://geojson.org/geojson-ld/geojson-context.jsonld',
{'@version': '1.1',
'wx': 'https://api.weather.gov/ontology#',
's': 'https://schema.org/',
'geo': 'http://www.opengis.net/ont/geosparql#',
'unit': 'http://codes.wmo.int/common/unit/',
'@vocab': 'https://api.weather.gov/ontology#',
'geometry': {'@id': 's:GeoCoordinates', '@type': 'geo:wktLiteral'},
'city': 's:addressLocality',
'state': 's:addressRegion',
'distance': {'@id': 's:Distance', '@type': 's:QuantitativeValue'},
'bearing': {'@type': 's:QuantitativeValue'},
'value': {'@id': 's:value'},
'unitCode': {'@id': 's:unitCode', '@type': '@id'},
'forecastOffice': {'@type': '@id'},
'forecastGridData': {'@type': '@id'},
'publicZone': {'@type': '@id'},
'county': {'@type': '@id'}}],
'id': 'https://api.weather.gov/points/39.9778,-105.275',
'type': 'Feature',
'geometry': {'type': 'Point', 'coordinates': [-105.275, 39.9778]},
'properties': {'@id': 'https://api.weather.gov/points/39.9778,-105.275',
'@type': 'wx:Point',
'cwa': 'BOU',
'type': 'land',
'forecastOffice': 'https://api.weather.gov/offices/BOU',
'gridId': 'BOU',
'gridX': 54,
'gridY': 73,
'forecast': 'https://api.weather.gov/gridpoints/BOU/54,73/forecast',
'forecastHourly': 'https://api.weather.gov/gridpoints/BOU/54,73/forecast/hourly',
'forecastGridData': 'https://api.weather.gov/gridpoints/BOU/54,73',
'observationStations': 'https://api.weather.gov/gridpoints/BOU/54,73/stations',
'relativeLocation': {'type': 'Feature',
'geometry': {'type': 'Point', 'coordinates': [-105.249081, 39.939266]},
'properties': {'city': 'Eldorado Springs',
'state': 'CO',
'distance': {'unitCode': 'wmoUnit:m', 'value': 4820.7565022562},
'bearing': {'unitCode': 'wmoUnit:degree_(angle)', 'value': 332}}},
'forecastZone': 'https://api.weather.gov/zones/forecast/COZ035',
'county': 'https://api.weather.gov/zones/county/COC013',
'fireWeatherZone': 'https://api.weather.gov/zones/fire/COZ215',
'timeZone': 'America/Denver',
'radarStation': 'KFTG',
'astronomicalData': {'sunrise': '2026-04-07T06:33:30-06:00',
'sunset': '2026-04-07T19:32:46-06:00',
'transit': '2026-04-07T13:03:08-06:00',
'civilTwilightBegin': '2026-04-07T06:07:19-06:00',
'civilTwilightEnd': '2026-04-07T19:58:57-06:00',
'nauticalTwilightBegin': '2026-04-07T05:34:31-06:00',
'nauticalTwilightEnd': '2026-04-07T20:31:45-06:00',
'astronomicalTwilightBegin': '2026-04-07T05:00:28-06:00',
'astronomicalTwilightEnd': '2026-04-07T21:05:48-06:00'},
'nwr': {'transmitter': 'WXM51',
'sameCode': '008013',
'areaBroadcast': 'https://api.weather.gov/radio/WXM51/broadcast',
'pointBroadcast': 'https://api.weather.gov/points/39.9778,-105.275/radio'}}}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}")<class 'dict'>
key: @context
value: ['https://geojson.org/geojson-ld/geojson-context.jsonld', {'@version': '1.1', 'wx': 'https://api.weather.gov/ontology#', 's': 'https://schema.org/', 'geo': 'http://www.opengis.net/ont/geosparql#', 'unit': 'http://codes.wmo.int/common/unit/', '@vocab': 'https://api.weather.gov/ontology#', 'geometry': {'@id': 's:GeoCoordinates', '@type': 'geo:wktLiteral'}, 'city': 's:addressLocality', 'state': 's:addressRegion', 'distance': {'@id': 's:Distance', '@type': 's:QuantitativeValue'}, 'bearing': {'@type': 's:QuantitativeValue'}, 'value': {'@id': 's:value'}, 'unitCode': {'@id': 's:unitCode', '@type': '@id'}, 'forecastOffice': {'@type': '@id'}, 'forecastGridData': {'@type': '@id'}, 'publicZone': {'@type': '@id'}, 'county': {'@type': '@id'}}]
key: id
value: https://api.weather.gov/points/39.9778,-105.275
key: type
value: Feature
key: geometry
value: {'type': 'Point', 'coordinates': [-105.275, 39.9778]}
key: properties
value: {'@id': 'https://api.weather.gov/points/39.9778,-105.275', '@type': 'wx:Point', 'cwa': 'BOU', 'type': 'land', 'forecastOffice': 'https://api.weather.gov/offices/BOU', 'gridId': 'BOU', 'gridX': 54, 'gridY': 73, 'forecast': 'https://api.weather.gov/gridpoints/BOU/54,73/forecast', 'forecastHourly': 'https://api.weather.gov/gridpoints/BOU/54,73/forecast/hourly', 'forecastGridData': 'https://api.weather.gov/gridpoints/BOU/54,73', 'observationStations': 'https://api.weather.gov/gridpoints/BOU/54,73/stations', 'relativeLocation': {'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [-105.249081, 39.939266]}, 'properties': {'city': 'Eldorado Springs', 'state': 'CO', 'distance': {'unitCode': 'wmoUnit:m', 'value': 4820.7565022562}, 'bearing': {'unitCode': 'wmoUnit:degree_(angle)', 'value': 332}}}, 'forecastZone': 'https://api.weather.gov/zones/forecast/COZ035', 'county': 'https://api.weather.gov/zones/county/COC013', 'fireWeatherZone': 'https://api.weather.gov/zones/fire/COZ215', 'timeZone': 'America/Denver', 'radarStation': 'KFTG', 'astronomicalData': {'sunrise': '2026-04-07T06:33:30-06:00', 'sunset': '2026-04-07T19:32:46-06:00', 'transit': '2026-04-07T13:03:08-06:00', 'civilTwilightBegin': '2026-04-07T06:07:19-06:00', 'civilTwilightEnd': '2026-04-07T19:58:57-06:00', 'nauticalTwilightBegin': '2026-04-07T05:34:31-06:00', 'nauticalTwilightEnd': '2026-04-07T20:31:45-06:00', 'astronomicalTwilightBegin': '2026-04-07T05:00:28-06:00', 'astronomicalTwilightEnd': '2026-04-07T21:05:48-06:00'}, 'nwr': {'transmitter': 'WXM51', 'sameCode': '008013', 'areaBroadcast': 'https://api.weather.gov/radio/WXM51/broadcast', 'pointBroadcast': 'https://api.weather.gov/points/39.9778,-105.275/radio'}}
The closest forecast office from the NCAR Mesa Lab is forecastOffice
ncar_weather.json()["properties"]["forecastOffice"]'https://api.weather.gov/offices/BOU'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'https://api.weather.gov/gridpoints/BOU/54,73/forecast/hourly'ncar_forecast_hourly = requests.get(ncar_forecast_url)
ncar_forecast_hourly.status_code200Note
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()dict_keys(['number', 'name', 'startTime', 'endTime', 'isDaytime', 'temperature', 'temperatureUnit', 'temperatureTrend', 'probabilityOfPrecipitation', 'dewpoint', 'relativeHumidity', 'windSpeed', 'windDirection', 'icon', 'shortForecast', 'detailedForecast'])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)2026-04-06T19:00:00-06:00
2026-04-13T07:00:00-06:00
# 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)[64, 61, 56, 54, 51, 49, 46, 45, 43, 41, 40, 40, 39, 43, 45, 50, 54, 59, 62, 66, 67, 67, 68, 66, 63, 62, 59, 58, 57, 56, 55, 53, 52, 50, 49, 49, 51, 55, 58, 61, 64, 66, 68, 69, 69, 69, 69, 67, 65, 62, 59, 57, 56, 54, 52, 50, 48, 46, 45, 45, 47, 51, 55, 59, 63, 66, 68, 69, 70, 69, 68, 65, 62, 60, 58, 57, 56, 55, 53, 51, 49, 48, 47, 47, 48, 50, 53, 56, 59, 62, 64, 65, 66, 66, 66, 65, 63, 61, 59, 58, 56, 55, 54, 52, 51, 50, 49, 49, 51, 54, 58, 62, 65, 68, 70, 70, 70, 69, 67, 65, 63, 61, 59, 58, 57, 56, 55, 53, 52, 51, 51, 51, 53, 55, 58, 61, 64, 66, 67, 68, 68, 67, 66, 64, 62, 60, 58, 57, 56, 55, 54, 52, 51, 49, 48, 48]
# 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.