Skip to article frontmatterSkip to article content

API Basics


Overview

This notebook will cover the terminology and steps needed to retrieve data from an API

  1. Prerequisites
  2. Motivation
  3. API Terminology (and Status Codes)
  4. Imports
  5. Example: Weather API
  6. Summary

Prerequisites

ConceptsImportanceNotes
Intro to PandasNecessaryFamiliarity with working with dataframes
Intro to MatplotlibHelpfulPlotting 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 data
  • GET: A GET request retrieves data
  • SET: 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.